PostsController 中的 NoMethodError#create undefined method `latitude=' "saving lat and long to connected tables!!"
NoMethodError in PostsController#create undefined method `latitude=' "saving lat and long to connected tables!!"
我正在尝试 post 我用回形针上传的图像元数据中的这些坐标到另一个 table 地方。"so coordinates go to places table." 这些地方有纬度和经度列table。提交后 post 我 运行 进入这个错误。错误的突出显示部分是 self.latitude=parse_latlong(等....)。
post_id 是 table 处的外键。当我在 post table 中有纬度和经度时,这以前有效。但现在我给了它自己的 table 以获得更好的数据库结构。如果这是主要问题,我只需要知道如何让我的 post 控制器与我的 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
post 控制器
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
post 型号
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 提取中将纬度和经度变量更新到数据库中。提取不是问题,但我相信我将该信息保存到数据库中的方式是真实的问题!!!谢谢!!!
而不是:
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'])
)
问题似乎源于您正在更新关联模型的属性。您可以通过调用
update_attributes(place_attributes: {latitude: , longitude: })
但我建议将此逻辑排除在 posts 模型之外,这对于将原始用户输入转换为数据库可使用格式的表单模型来说确实是一个问题。如果您不想向您的应用程序添加额外的层,至少将这些方法移动到它们自己的模型中。
每次,您都会看到一组私有方法互相调用并传递状态,我认为这是一个好兆头,它们应该 class:
所以
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 参数中:
@post = current_user.posts.build(post_params.merge(place_params))
这种方法的好处是您引入了一个具有明确责任的对象,并作为单纯的数据库包装器返回到 AR 模型。一般来说,我尝试将更复杂的交互封装在某种服务对象中,但在简单的情况下,您的控制器可以扮演中介者的角色,协调系统中不同对象的交互方式。
我正在尝试 post 我用回形针上传的图像元数据中的这些坐标到另一个 table 地方。"so coordinates go to places table." 这些地方有纬度和经度列table。提交后 post 我 运行 进入这个错误。错误的突出显示部分是 self.latitude=parse_latlong(等....)。
post_id 是 table 处的外键。当我在 post table 中有纬度和经度时,这以前有效。但现在我给了它自己的 table 以获得更好的数据库结构。如果这是主要问题,我只需要知道如何让我的 post 控制器与我的 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
post 控制器
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
post 型号
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 提取中将纬度和经度变量更新到数据库中。提取不是问题,但我相信我将该信息保存到数据库中的方式是真实的问题!!!谢谢!!!
而不是:
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'])
)
问题似乎源于您正在更新关联模型的属性。您可以通过调用
update_attributes(place_attributes: {latitude: , longitude: })
但我建议将此逻辑排除在 posts 模型之外,这对于将原始用户输入转换为数据库可使用格式的表单模型来说确实是一个问题。如果您不想向您的应用程序添加额外的层,至少将这些方法移动到它们自己的模型中。 每次,您都会看到一组私有方法互相调用并传递状态,我认为这是一个好兆头,它们应该 class: 所以
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 参数中:
@post = current_user.posts.build(post_params.merge(place_params))
这种方法的好处是您引入了一个具有明确责任的对象,并作为单纯的数据库包装器返回到 AR 模型。一般来说,我尝试将更复杂的交互封装在某种服务对象中,但在简单的情况下,您的控制器可以扮演中介者的角色,协调系统中不同对象的交互方式。