I have kind of a tricky problem I'm working on in my current rails app. In my app users share photos. Photos can be associated with a city, so City has_many :photos
. I want users to be able to associate their photos with a city using autocomplete and a natural language syntax. Ie: New York, NY or Paris, France.
I'd like to do this with an autocomplete text box so that if the user types "Athens" they would see a list with:
Athens, Greece
Athens, GA
... and if the person actually wanted "Athens, TX" they could simply type that in and it would create a new city record.
My city model has the fields, name, state, country
. State and Country are 2-letter postal codes (I use Carmen to validate them). I have a virtual attribute called full_name
which returns "City, State Code" (like New York, NY) for North American cities, and "City, Country Name" (like Paris, France) for all others.
def full_name
if north_american?
[name, state].join(', ')
else
[name, Carmen.country_name( country )].join(', ')
end
end
def north_american?
['US','CA'].include? country
end
My question is, to get the text field working, how can I create a find_or_create method that can accept a string with the city name and either state code or country name and find or create that record?
Update
Inspired by Kandada's answer I came up with something a little different:
def self.find_or_create_by_location_string( string )
city,second = string.split(',').map(&:strip)
if second.length == 2
country = self.country_for_state( second )
self.find_or_create_by_name_and_state( city, second.upcase, :country => country )
else
country = Carmen.country_code(second)
self.find_or_create_by_name_and_country( city, country )
end
end
def self.country_for_state( state )
if Carmen.state_codes('US').include? state
'US'
elsif Carmen.state_codes('CA').include? state
'CA'
else
nil
end
end
This is rocking my specs right now, so I think my issue is solved.
class Photo < ActiveRecord::Base
attr_accessor :location
def self.location_hash location
city,state,country = location.split(",")
country = "US" if country.blank?
{:city => city, :state => state, :country => :country}
end
end
Now you can 'find_or_create_by_*'
Photo.find_or_create_by_name(
Photo.location_hash(location).merge(:name => "foor bar")
)