正确的地理编码器验证回调

Correct callbacks for geocoder validation

我希望这不是骗人的,但由于到目前为止我还没有找到令人满意的答案,所以我要提出我的问题。我是 rails 初学者所以请对我温柔一点 ;)

对于小型地图项目,我们使用地理编码器 gem。我们有一个模型 Place 包含 :street:house_number:postal_code:city 并被 :address 包裹为一个简单的字符串作为虚拟属性正在传递给地理编码器。我们正在使用 nominatim(-> OSM 数据)进行查询。与 google API nominatim returns nil 不同,如果给定地址不对应于 lat/lon 对。到目前为止我们的模型文件看起来像这样

class Place < ActiveRecord::Base
  has_many :descriptions, :dependent => :delete_all
  accepts_nested_attributes_for :descriptions

  geocoded_by :address
  before_validation :geocode

  validates :address, presence: true
  validates :name, presence: true
  validates :longitude, presence: true,
                        numericality: { less_than_or_equal_to: 90, greater_than_or_equal_to: -90 }
  validates :latitude, presence: true,
                       numericality: { less_than_or_equal_to: 180, greater_than_or_equal_to: -180 }
  validates :categories, presence: true

  def address
    ["#{self.street} #{self.house_number}", self.postal_code, self.city].join(', ')
  end
end

与我看过的大多数示例不同,我使用的是 before_validation :geocode,因为否则 lat 和 lon 在被评估之前将为 nil 并引发验证错误(不存在)。 到目前为止,这适用于创建新位置,但我无法修改验证以使其适用于我的控制器内的 update 操作。基本上我想检查应用于 address 的更改是否有效(即 API 是否找到给定地址的 lat/lon 对)。研究我发现的文档,我做了一个像 before_validate :geocode, if: :address_changed? 这样的条件回调,但是由于更新请求的参数在我的模型中不可用,我不知道如何检查它。如果有任何提示,我会很高兴!

编辑:

下面接受的答案是正确的,但没有立即生效,因为在我的控制器中我使用的是 update 而不是 update_attributes

您的模型不需要知道更新请求的参数。您可以通过检查构成地址的任何列是否已更改来检查地址是否已更改。由于 address 不是列,因此您需要像这样定义 address_changed?

before_validation :geocode, if: :address_changed?

def address_changed?
  street_changed? || house_number_changed? || postal_code_changed? || city_changed?
end

请注意,streethouse_numbercitypostal_code 都需要是列才能使上述操作生效。