问题
I have a model with an address field that needs to be unique:
class AddressMeta < AR::Base
def normalize
# normalize and store full_address
end
validates_uniqueness_of :full_address
after_validation :normalize
end
I am passing addresses through a geocoding API to ensure that they are valid and normalized before storing. The trouble I'm running into is that I also want addresses to be unique, so there's only a single record per unique address string. Take the following addresses:
101 E 1st St #101, Austin, TX
101 E 1st Street Suite 101, Austin, TX
These two are obviously the same address, but I can't find the second in the database unless it is first normalized to match the first. So if the first one exists and I run a find_or_create_by(full_address: address) call on the second, I end up missing with the search and creating a new object, and this results in a collision.
So - my question. In Rails/AR, how can I normalize the input to the find_or_create_by method prior to performing the search? Or is there a better way to handle the case that I have a collision on a unique field after normalizing a field?
回答1:
It's difficult to determine without the full context of the code, however one solution is to change the normalize execution to occur before validation and not after:
class AddressMeta < AR::Base
validates_uniqueness_of :full_address
before_validation do
full_address = normalize_address(full_address)
end
private
def normalize_address(address_string)
# Code to convert address with API
# Returns normalized address string
end
end
That way the uniqueness validator should work. Also, a nice little refactor would be to extract the address normalization logic out into its own class:
# lib/address_converter.rb
class AddressConverter
class << self
def normalize(raw_address)
# Logic and API Code
# Returns normalized string
end
end
end
# app/models/address_meta.rb
require 'address_converter'
class AddressMeta < AR::Base
validates_uniqueness_of :full_address
before_validation do
full_address = AddressConverter::normalize(full_address)
end
end
来源:https://stackoverflow.com/questions/26855803/rails-normalize-before-find-or-create