I hope this is not a dupe but since I haven't found a satisfying answer so far I'm gonna put my question. I'm a rails beginner so please be gentle on me ;)
For a small mapping project we're using geocoder gem. We have a model Place
containing :street
, :house_number
, :postal_code
, :city
wrapped up as a simple string by :address
as the virtual attribute which is being passed to geocoder. We're doing the querying using nominatim (-> OSM data). Unlike the google API nominatim returns nil if the given address does not correspond to a lat/lon pair. So far our model file looks like this
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
Unlike most of the examples I've looked at I'm using before_validation :geocode
because otherwise lat and lon would be nil before they become evaluated raising a validation error (not present).
So far this works for creating new places but I'm unable to modify the validation to make it work for the update
action inside my controller. Basically I want to check if the changes applied to address
are valid (i.e. whether the API finds a lat/lon pair to the given address). Studying the documentation i found, that i do a conditional callback like before_validate :geocode, if: :address_changed?
but since the parameters of the update request are not available inside my model I have no clue how to check that. I'd be glad on any hint!
edit:
Accepted answer below is right, wasn't working instantly because inside my controller I was using update
instead of update_attributes
.
Your model doesn't need to know the parameters to update the request. You can check if the address changed by checking if any of the columns which make up your address have changed. Since address
isn't a column, you'll need to define address_changed?
like so:
before_validation :geocode, if: :address_changed?
def address_changed?
street_changed? || house_number_changed? || postal_code_changed? || city_changed?
end
Note that street
, house_number
, city
and postal_code
will all need to be columns in order for the above to work.