Using Geocoder, is there a way to save out the street name, city and zip to seperate columns? - ruby-on-rails-3

I'm in the process of switching my app to use geocoder. In my places table I have columns for address, lat, lng, street_address, city & zip. Using geocoder I'm happily able to fill lat, lng & address columns after validation with with the following in my places model
attr_accessible :address, :lat, :lng
geocoded_by :address, :latitude => :lat, :longitude => :lng
after_validation :geocode, :if => :address_changed?
Is there a way to also have geocoder add the street name, city and zip to three other, separate columns?

I'm still newish to rails so I missed this at first, but hope this helps someone else.
in my model
geocoded_by :address do |obj,results|
if geo = results.first
obj.city = geo.city
obj.lat = geo.latitude
obj.lng = geo.longitude
obj.zip = geo.postal_code
obj.state = geo.state
obj.country = geo.country_code
end
end
and in my view
#tonic.address = params[:address]

Related

Find coordinates for my database's address column

I have my own database that includes: address, lat, long, name.
I have all the addresses that I want without their coordinates. Is there a way to find the coordinates in order to use them as markers on my active map?
In other words I want something to batch?! geocode my addresses that are already in to my database.
Thank you very much
Edited:
def index
if params[:search].present?
#locations = Location.near(params[:search], 20, :order => :distance)
else
#locations = Location.all
#locations.each do |l|
if l.latitude.nil?
new_location = "#{l.address}"
s = Geocoder.search(new_location)
l.latitude = s[0].latitude
l.longitude = s[0].longitude
l.save
end
end
end
This is what I have, but it updates only my first address on the database.
Check out the gmaps4rails gem at https://github.com/apneadiving/Google-Maps-for-Rails
Here's what I use in the model one of my apps:
acts_as_gmappable lat: 'latitude', lng: 'longitude',
process_geocoding: :geocode?,
address: :full_address,
msg: "Sorry, not even Google could figure out where that is"
Oh, and here's my geocode? method:
def geocode?
latitude.blank? || longitude.blank?
end
So when the model's latitude and/or longitude are nil, gmaps4rails automatically does a lookup and fills in the entries.

Rails 3 geocoder and the filtering an object

I'm trying to get the geocoder gem to work on an object that has been filtered using a has_many relationship
like so
user.rb
has_one :profile
has_many :roles
name:string
profile.rb
belongs_to :user
latitude,latitude:float, address:string, city:string
role.rb
belongs_to :user
name:string
the problem I'm having is I need to filter the roles to say id => 3
so we have
#limitrole = User.includes(:profile, :roles).where('roles.id' => 3)
this returns an object of limited roles, now grab the profile that contains the geocode stuff
#profiles = #limitrole.collect { |user| user.profile }
This returns an object of addresses limited to the users role
But this won't work
#findlocations = #profiles.near('city, country', 20) (city and country being arbitrary values)
Yet this will work
#findlocations = Profile.near('city, country', 20)
#profiles should be the same as Profile (both objects) it's just #profiles has been filtered.
How do I get this to work?
This might not be railsy but this is how I got it to work
first grabbing the form fields
#findaddress = params[:profile][:profileaddress] + ", " + params[:profile][:profilecity]
Next I grabbed a list of the users based on their role
#limituser = User.includes(:profile, :roles).where('roles.id' => 3)
next using the geocoder (railscast #273) plugin I create a list of all the geocoded addresses that are near the locations specified in the form (#findaddress) and grab the user_id
#findlocations = Profile.near(#findaddress, 20).pluck(:user_id)
Now I can create a list of users filtered by their role and address specified by a form field
#filteruser = #limituser.where(:id => #findlocations)

Rails 3 validates_uniquess_of virtual field with scope

I am working on a Rails 3 app that is needing to run a validation on a virtual field to see if the record already exists... here is my model code:
#mass-assignment
attr_accessible :first_name, :last_name, :dob, :gender
#validations
validates_presence_of :first_name, :last_name, :gender, :dob
validates :fullname, :uniqueness => { :scope => [:dob] }
def fullname
"#{first_name} #{last_name}"
end
I am not getting any errors, its passing the validation.
I don't think you can do something like that with standard validates. Reason is, it usually is a "simple" sql look-up for uniqueness. But to check uniqueness of what's sent back from your method, it'd have to :
Get all entries of your scope
For each, execute the fullname method.
Add every result in an array while testing for uniqueness
Simple when the data set is small, but then it'd just take ages to do as soon as you reach 10K plus matches in your scope.
I'd personally do this with a standard before_save using the dob scope
before_save :check_full_name_uniqueness
def check_full_name_uniqueness
query_id = id || 0
return !Patient.where("first_name = ? and last_name = ? and dob = ? and id != ?", first_name, last_name, dob, query_id).exists?
end
Add error message (before the return):
errors.add(:fullname, 'Your error')
Back in the controller, get the error :
your_object.errors.each do |k, v| #k is the key of the hash, here fullname, and v the error message
#Do whatever you have to do
end

MongoMapper and Gmaps4Rails - Mapping location indexed array field to acts_as_gmappable

I have a model that's backed by Mongodb and I'm trying to get Gmaps4Rails to be able to properly use a location indexed array field that's in my mongo document.
I'm failing to figure out how I should map this given that the latitude and longitude aren't stored as independent values in order to take advantage of the geoindexing on mongo:
class Site
include MongoMapper::Document
include Gmaps4rails::ActsAsGmappable
acts_as_gmappable :lat => ???,
:lon => ???,
:process_geocoding => false
key :name, String
key :location, Array
ensure_index [[:location, '2d']]
end
for now I'm just doing this:
class Site
include MongoMapper::Document
include Gmaps4rails::ActsAsGmappable
acts_as_gmappable :process_geocoding => false
key :name, String
key :location, Array
ensure_index [[:location, '2d']]
def lat
return latitude
end
def lon
return longitude
end
def latitude
return location[1]
end
def longitude
return location[0]
end
end

Rails3: Unable to update attribute without first reloading record when creating parent dynamically

Summary
Where City has many Locations (HABTM association), create a child record like this:
a = Location.create(:name=>'Site 1', :city => City.create(:name=>'A City'))
Issue: a.city_id can't be changed in the database until a has been reloaded. Example:
a.city_id = 99
a.save # => true
a.city_id # => 11
Details
class City < ActiveRecord::Base
has_many :locations
end
class Location < ActiveRecord::Base
belongs_to :city
end
a = Location.create(:name=>'Site 1', :city => City.create(:name=>'A City'))
# Create a record manually for comparison
b = Location.create(:name=>a.name, :city_id=>a.city_id)
a.city_id = 99
a.save # => true
b.city_id = 99
b.save # => true
a.city_id # => 11
b.city_id # => 99
Both a and b appear identical on creation but behave differently. Although a is shown as valid after changing the city_id, and is saved successfully, the city_id is not changed.
However, if the record a is reloaded before it is changed, the change "works":
a = Location.create(:name=>'Site 1', :city => City.create(:name=>'A City'))
a.reload
a.city_id = 99
a.save
a.city_id # => 99
This might seem rather arcane, since one can simply create the parent object first, but I discovered the issue using FactoryGirl,
factory :city do
name 'Jos'
end
factory :location do
name 'Site 1'
city { |a| a.association :city }
end
Factory(:location) shows the same behavior of having an unchangeable :city_id until it's reloaded from the database. It took a long time before I figured out what was going on, why my tests were failing because of the change not happening as I expected.
I see from inspecting the new location that it contains an entire city object, while after the reload it does not, so that must be a clue, but what exactly is going on here? Would it be reasonable to expect FactoryGirl to automatically reload the object before returning, or would that break something? Of course I could do that with a callback, but I'm interested in simplicity.
(If you wonder why I don't just say location.city = new_city rather than location.city_id = 99, it's because I was writing a test and wanted to create "orphan" records with invalid references.)