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=' "将经纬度保存到连接的表中!!"的主要内容,如果未能解决你的问题,请参考以下文章