PostsController 中的 NoMethodError#create undefined method `latitude=' "将经纬度保存到连接的表中!!"

Posted

技术标签:

【中文标题】PostsController 中的 NoMethodError#create undefined method `latitude=\' "将经纬度保存到连接的表中!!"【英文标题】:NoMethodError in PostsController#create undefined method `latitude=' "saving lat and long to connected tables!!"PostsController 中的 NoMethodError#create undefined method `latitude=' "将经纬度保存到连接的表中!!" 【发布时间】:2016-05-07 10:36:22 【问题描述】:

我正在尝试将这些坐标从我用回形针上传的图像的元数据中发布到另一个名为地点的表中。“所以坐标转到地点表。”地点表中有纬度和经度列。提交帖子后,我遇到了这个错误。错误中突出显示的部分是 self.latitude=parse_latlong(etc....)。

post_id 是places 表中的外键。当我在帖子表中有纬度和经度时,这以前有效。但现在我给了它自己的表以获得更好的数据库结构。如果这是主要问题,我只需要知道如何让我的后控制器与我的场所控制器一起工作??

地点控制器

class PlacesController < ApplicationController
    before_action :set_post

def create  
  @place = @post.places.build(place_params)


  if @place.save
    flash[:success] = "coorinates saved"
    redirect_to :back
  else
    flash[:alert] = "Check the form, something went wrong."
    render root_path
  end
end


private

def place_params  
  params.require(:place).permit(:continent, :country, :city, :address, :latitude, :longitude)
end

def set_post  
  @post = Post.find(params[:post_id])
end  
end

后控制器

class PostsController < ApplicationController

before_action :authenticate_user!, :except => [:show, :index, :new]

before_action :set_post, only: [:show, :edit, :update, :destroy]

before_action :owned_post, only: [:edit, :update, :destroy]  

  def index
    @post = Post.new
    @posts = Post.all
  end

  def show

    @post = Post.find(params[:id])
  end

  def new
    @post = current_user.posts.build

    @posts = Post.all
  end

  def create
     @post = current_user.posts.build(post_params)

     if @post.save
      flash[:success] = "Your post has been created!"
      redirect_to root_path
    else
      flash[:alert] = "Your new post couldn't be created!  Please check the form."
      render :new
    end
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
     if @post.update(post_params)
      flash[:success] = "Post updated."
      redirect_to root_path
    else
      flash.now[:alert] = "Update failed.  Please check the form."
      render :edit
    end
  end

  def destroy
    @post.destroy
    flash[:success] = "Your Post has been removed."
    redirect_to root_path
  end

  private

  def post_params
    params.require(:post).permit(:image, :caption, :address)
  end

  def set_post
    @post = Post.find(params[:id])
  end

  def owned_post  
  unless current_user == @post.user
    flash[:alert] = "That post doesn't belong to you!"
    redirect_to root_path
  end
end  

end

发布模型

class Post < ActiveRecord::Base

belongs_to :user
belongs_to :place

has_many :comments, dependent: :destroy
has_one :place, dependent: :destroy

    validates :user_id, presence: true
    validates :image, presence: true


accepts_nested_attributes_for :place

  has_attached_file :image, styles:  :medium => "640x" 

  validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/

after_post_process :save_latlong


private

  def save_latlong
  exif_data = MiniExiftool.new(image.queued_for_write[:original].path)
  self.latitude = parse_latlong(exif_data['gpslatitude'])
  self.longitude = parse_latlong(exif_data['gpslongitude'])
end

def parse_latlong(latlong)
  return unless latlong
  match, degrees, minutes, seconds, rotation = /(\d+) deg (\d+)' (.*)" (\w)/.match(latlong).to_a
  calculate_latlong(degrees, minutes, seconds, rotation)
end

def calculate_latlong(degrees, minutes, seconds, rotation)
  calculated_latlong = degrees.to_f + minutes.to_f/60 + seconds.to_f/3600
  ['S', 'W'].include?(rotation) ? -calculated_latlong : calculated_latlong
end


end

总而言之,我希望通过 exif 提取将纬度和经度变量更新到数据库中。提取不是问题,而是我相信如何将信息保存到数据库中才是真正的问题! !!谢谢!!!!

【问题讨论】:

【参考方案1】:

问题似乎源于您正在更新关联模型的属性这一事实。你可以通过调用

update_attributes(place_attributes: latitude: , longitude: )

但我建议将此逻辑排除在帖子模型之外,这对于将原始用户输入转换为数据库可使用格式的表单模型确实是一个问题。如果您不想在应用程序中添加额外的层,至少将这些方法移动到它们自己的模型中。 每次,您都会看到一组私有方法相互调用并传递状态,我认为这是一个好兆头,它们应该用于一个类: 所以

class LotLangParser

  def initialize(image)
    @image = image
    @exif_data = MiniExiftool.new(image.queued_for_write[:original].path)
  end

  def lat
    parse_latlong(exif_data['gpslatitude'])
  end

  def lon
    parse_latlong(exif_data['gpslongitude'])
  end

  private

  def parse_latlong(latlong)
    return unless latlong
    match, degrees, minutes, seconds, rotation = /(\d+) deg (\d+)' (.*)" (\w)/.match(latlong).to_a
    calculate_latlong(degrees, minutes, seconds, rotation)
  end

  def calculate_latlong(degrees, minutes, seconds, rotation)
    calculated_latlong = degrees.to_f + minutes.to_f/60 + seconds.to_f/3600
    ['S', 'W'].include?(rotation) ? -calculated_latlong : calculated_latlong
  end
end

作为说明,我还将封装 MiniExiftool 并将其作为依赖项注入到构造函数中。但我们不要忘记我们的目标。

然后在你的控制器中你可以调用你的解析器给你位置参数

def place_params
  long_lat_parser = LongLatParser(image)
  place_attributes: longitude:  long_lat_parser.lon,  latitude: long_lat_parser.lat
end

然后简单地将它们合并到帖子参数中:

@post = current_user.posts.build(post_params.merge(place_params))

这种方法的好处是您引入了一个具有明确责任的对象,并作为单纯的数据库包装器返回到 AR 模型。一般来说,我会尝试将更复杂的交互封装在某种服务对象中,但在简单的情况下,您的控制器可以扮演协调者的角色,协调系统中不同对象的交互方式。

【讨论】:

好吧!是的,我之前试图移动到放置模型,但是我怎样才能做到这一点而不会引发错误,我只移动私有部分并保留 after_post_process: save_latlong 吗?我在尝试学习时很难连接模型和控制器!! 是的,我认为这是一个普遍的缺点,框架对你没有多大帮助,看看这里使用表单模型(我现在在手机上,稍后我会用一个例子更新答案) robots.thoughtbot.com/activemodel-form-objects 你们俩都帮助了我,我把它全部搞定了。如果你认为我应该有不同的模型,而且你不介意给我看,那就太棒了!希望我能喜欢你们两个人的帖子!!!谢谢!!! 嘿,很高兴我能帮上忙,我编辑了我之前的答案,以举例说明如何从模型中提取解析逻辑,干杯 好的,我会这样做!这真的有助于我现在就实施它!谢谢!!!你也知道我是否可以在回形针收到附件时进行此运行。就像我选择一张图片然后这将运行。喜欢after_create?我应该把after_create 放到新班级吗?我想将其发布到 input div 中。【参考方案2】:

代替:

self.latitude = parse_latlong(exif_data['gpslatitude'])
self.longitude = parse_latlong(exif_data['gpslongitude'])

用途:

update_attributes(
  latitude: parse_latlong(exif_data['gpslatitude']),
  longitude: parse_latlong(exif_data['gpslongitude'])
)

【讨论】:

感谢您的快速回复!!!但是我收到另一个错误,它说 post 的未知属性错误未知属性“纬度”.....我相信这与我在 post 表中没有 long 或 lat 而是在 places 表中的事实有关跨度> 哦...嗯,是的,那是有道理的,哈哈!我用上面的代码解决的另一个问题是您的代码在更新后不会保存数据。所以你要么需要使用update_attributes,要么显式调用save 请注意,使用update_attributes 方法会跳过模型验证。如果这对您的用例来说是个问题,请改用save(或save!)。 好的!!那么我怎样才能将这些信息设置到 places 表呢?我不太擅长这部分哈哈。我假设我在控制器内做某事?或者我叫 place.latitude 什么的??

以上是关于PostsController 中的 NoMethodError#create undefined method `latitude=' "将经纬度保存到连接的表中!!"的主要内容,如果未能解决你的问题,请参考以下文章

Laravel5.1 搭建简单的社区--展示帖子页面

Laravel5.1 搭建简单的社区--发表帖子

Swift - 推送到新 ViewController 时的黑色底栏

数据表 + JSON + best_in_place

解析后显示元素

如何将自定义单元格放入另一个自定义单元格?