PostsController中的NoMethodError #create undefined方法`latitude =’“将lat和long保存到连接的表!!”

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

post_id是places表中的外键。 这在以前我在邮政表中有纬度和经度时起作用。 但现在我给它自己的表以更好的数据库结构..我只需要知道如何让我的post控制器与我的位置控制器一起工作,如果这是主要问题??

场所控制器

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  [: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  "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提取中将经纬度变量更新到数据库中..提取不是问题,而是我相信如何将这些信息保存到数据库中是真正的问题! 谢谢!!!!

问题似乎源于您正在从关联模型更新属性。 你可以通过电话来做到这一点

update_attributes(place_attributes: {latitude: , longitude: })

但我建议将这个逻辑保留在post模型之外,这实际上是表单模型的一个问题,您可以将原始用户输入转换为数据库可使用格式。 如果您不想在应用中添加其他图层,请至少将这些方法移动到自己的模型中。 每次,你都会看到一组私有方法互相调用并传递状态,我认为这是一个很好的信号,他们应该为一个类:所以

 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并将其作为构造函数中的依赖项注入。 但是,我们不要忘记我们的目标。

然后在您的控制器中,您可以调用解析器为您提供params

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

然后简单地将它们合并到post params中:

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

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

代替:

 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']) )