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

时间:2016-05-07 10:36:22

标签: ruby-on-rails ruby controller geolocation latitude-longitude

我正在尝试将使用回形针上传的图像的元数据中的这些坐标发布到另一个名为places的表格中。"所以坐标转到位置表格。"在places表中有列纬度和经度。提交帖子后我遇到了这个错误。突出显示的部分是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

All in All我想将exitude和经度变量从exif提取更新到数据库中..提取不是问题但我相信如何将该信息保存到数据库中是真的问题!!!谢谢!!!!

2 个答案:

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

然后在您的控制器中,您可以调用解析器为您提供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模型。一般来说,我尝试在某种服务对象中封装更复杂的交互,但在简单的情况下,您的控制器可以扮演调解器的角色,协调系统中不同对象的交互方式。

答案 1 :(得分:0)

而不是:

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