如何在 Rails before_save 回调中验证两个 Geocoder 对象的 distance_to 小于 200 mts?
How to validate that the distance_to of two Geocoder objects is less than 200 mts within a Rails before_save callback?
我是 RoR 初学者,我需要检查 user
和 gym
Geocoder 对象之间的距离是否小于 200 米,以便在数据库
这是我的代码:
app/models/check_in.rb
class CheckIn < ApplicationRecord
belongs_to :user
belongs_to :gym
before_save :check_in_distance
protected
def check_in_distance
gym = Gym.find_by(id: params[:gym_id])
distance_to_gym = gym.distance_to([43.9,-98.6])
if distance_to_gym < 200
return true
end
end
end
app/controllers/api/v1/check_inscontroller.rb
class Api::V1::CheckInsController < ApplicationController
before_action :authenticate_request!
def check_in
@check_in = CheckIn.create!(check_in_params.merge( user: current_user))
render json: CheckInBlueprint.render(@check_in, root: :data)
end
private
def check_in_params
params.require(:check_in).permit(:gym_id, :check_in_latitude,
:check_in_longitude)
end
end
您需要自定义验证而不是回调:
class CheckIn < ApplicationRecord
validate :distantance_to_gym
def distantance_to_gym
distance = gym.distance_to([check_in_latitude, check_in_longitude])
errors.add(:base, 'check in is too far from gym') if distance < 200
end
end
不要在控制器中使用 create!
。当然它非常适合惰性调试,但如果用户传递无效输入,它会引发异常。无效输入不是异常事件,不应将异常用于正常控制流。
诸如 .create!
之类的“bang”方法只能用于非交互式上下文,例如种子文件,在这些上下文中,不应期望创建记录会失败,或者将其包装在事务中以导致回滚.
使用正常的“非 bang”方法,例如 save
和 create
并检查记录是否实际保存并做出相应响应:
# see https://github.com/rubocop/ruby-style-guide#namespace-definition
module Api
module V1
class CheckInsController < ApplicationController
# this should be moved to the parent controller
# use a secure by default model where you opt out instead
before_action :authenticate_request!
def check_in
@check_in = CheckIn.new(check_in_params) do |c|
c.user = current_user
end
if @check_in.save
render json: CheckInBlueprint.render(@check_in, root: :data),
status: :created
else
render json: @check_in.errors.full_messages,
status: :unprocessable_entity
end
end
private
def check_in_params
params.require(:check_in).permit(:gym_id, :check_in_latitude,
:check_in_longitude)
end
end
end
end
我是 RoR 初学者,我需要检查 user
和 gym
Geocoder 对象之间的距离是否小于 200 米,以便在数据库
这是我的代码:
app/models/check_in.rb
class CheckIn < ApplicationRecord
belongs_to :user
belongs_to :gym
before_save :check_in_distance
protected
def check_in_distance
gym = Gym.find_by(id: params[:gym_id])
distance_to_gym = gym.distance_to([43.9,-98.6])
if distance_to_gym < 200
return true
end
end
end
app/controllers/api/v1/check_inscontroller.rb
class Api::V1::CheckInsController < ApplicationController
before_action :authenticate_request!
def check_in
@check_in = CheckIn.create!(check_in_params.merge( user: current_user))
render json: CheckInBlueprint.render(@check_in, root: :data)
end
private
def check_in_params
params.require(:check_in).permit(:gym_id, :check_in_latitude,
:check_in_longitude)
end
end
您需要自定义验证而不是回调:
class CheckIn < ApplicationRecord
validate :distantance_to_gym
def distantance_to_gym
distance = gym.distance_to([check_in_latitude, check_in_longitude])
errors.add(:base, 'check in is too far from gym') if distance < 200
end
end
不要在控制器中使用 create!
。当然它非常适合惰性调试,但如果用户传递无效输入,它会引发异常。无效输入不是异常事件,不应将异常用于正常控制流。
诸如 .create!
之类的“bang”方法只能用于非交互式上下文,例如种子文件,在这些上下文中,不应期望创建记录会失败,或者将其包装在事务中以导致回滚.
使用正常的“非 bang”方法,例如 save
和 create
并检查记录是否实际保存并做出相应响应:
# see https://github.com/rubocop/ruby-style-guide#namespace-definition
module Api
module V1
class CheckInsController < ApplicationController
# this should be moved to the parent controller
# use a secure by default model where you opt out instead
before_action :authenticate_request!
def check_in
@check_in = CheckIn.new(check_in_params) do |c|
c.user = current_user
end
if @check_in.save
render json: CheckInBlueprint.render(@check_in, root: :data),
status: :created
else
render json: @check_in.errors.full_messages,
status: :unprocessable_entity
end
end
private
def check_in_params
params.require(:check_in).permit(:gym_id, :check_in_latitude,
:check_in_longitude)
end
end
end
end