views:

218

answers:

2

I have a Rails application that lists information about local services. My objectives for this model are as follows: 1. Require the name and tag_list fields. 2. Require one or more of the tollfreephone, phone, phone2, mobile, fax, email or website fields. 3. If the paddress field has a value, then encode it with the Geokit plugin. Here is my entry.rb model:

class Entry < ActiveRecord::Base

  validates_presence_of :name, :tag_list
  validates_presence_of :tollfreephone or :phone or :phone2 or :mobile or :fax or :email or :website
  acts_as_taggable_on :tags
  acts_as_mappable :auto_geocode=>{:field=>:paddress, :error_message=>'Could not geocode physical address'}

  before_save :geocode_paddress
  validate :required_info

  def required_info
    unless phone or phone2 or tollfreephone or mobile or fax or email or website
      errors.add_to_base "Please have at least one form of contact information."
    end
  end

  private
  def geocode_paddress
    #if paddress_changed?
    geo=Geokit::Geocoders::MultiGeocoder.geocode (paddress)
    errors.add(:paddress, "Could not Geocode address") if !
geo.success
    self.lat, self.lng = geo.lat,geo.lng if geo.success
    #end 
  end
end

Requiring name and tag_list work, but requiring one (or more) of the tollfreephone, phone, phone2, mobile, fax, email or website fields does not.

As for encoding with Geokit, in order to save a record with the model I have to enter an address. Which is not the behavior I want. I would like it to not require the paddress field, but if the paddress field does have a value, it should encode the geocode. As it stands, it always tries to geocode the incoming entry. The commented out "if paddress_changed?" was not working and I could not find something like "if paddress_exists?" that would work.

Help with any of these issues would be greatly appreciated. I posted three questions pertaining to my model because I'm not sure if they are preventing each other from working. Thank you for reading my questions.

A: 

I don't have ruby on here, but I'm pretty sure you can't do that with validates_presence_of.

You'll need to do something like:

validates_presence_of :tollfreephone, :unless => some_method_to_tell_if_other_methods_are_there

As for the geocoder method, maybe just check if it's nil? Something like:

def geocode_paddress
    if paddress != nil
        geo = Geokit::Geocoders::MultiGeocoder.geocode (paddress)
        if geo.success
           self.lat, self.lng = geo.lat,geo.lng
        else
           errors.add(:paddress, "Could not Geocode address")
        end
    end
end
Sheeo
This code will fail unless you return after successful geo-coding. Otherwise `errors.add` will be called regardless of success/failure of geo-coding.
KandadaBoggu
My indentation was off. Pretty sure it would work--haven't tests.Please confirm
Sheeo
I think you are missing an `end` for the `geo.success` `if` check.
KandadaBoggu
Right. Time to get some sleep -- thanks.Your answer is much better anyway -- stick with that :)
Sheeo
I know the feeling :-)
KandadaBoggu
+3  A: 

I see following problems in your code:

1) Duplicate presence checks

2) Auto and manual geo coding at the same time.

Here is a version of your code that might work:

class Entry < ActiveRecord::Base

  acts_as_mappable 
  acts_as_taggable_on   :tags

  validates_presence_of :name, :tag_list
  validate              :required_info

  before_save           :geocode_paddress


private

  def required_info
    if( phone.empty?  and phone2.empty? and tollfreephone.empty? and 
        mobile.empty? and fax.empty?    and email.empty?         and 
        website.empty? 
      ) 
      errors.add_to_base "Please have at least one form of contact information."
    end
  end


  def geocode_paddress
    # if paddress is nil or empty set the old values to nil and return    
    ((self.lat = self.lng = nil); return true) if paddress.empty?
    g=Geokit::Geocoders::MultiGeocoder.geocode(paddress)
    (errors.add(:paddress,"Could not Geocode address");
       return false) unless g.success
    self.lat, self.lng = g.lat, g.lng
  end
end

Edit

The required_info validation fails as the input data submitted by the form contains empty strings for missing fields rather than null values. Hence the phone or phone2 etc. check always returned true. I have changed the validation code to address this edge case. I am quite sure it will work now.

PS: This is a typical scenario where you should be using a debugger. Download and play with any free IDE like Aptana Radrails OR Netbeans. Once you are familiar with the tool you will be able to easily debug such issues.

KandadaBoggu
When I use the exact code above, and try to create a new entry with just a name and a tag it successfully creates an entry without errors. When really it should be saying: "Please have at least one form of contact information."I also tested adding one of phone, phone2, tollfreephone, mobile, fax, email, or website and it successfully creates it every time. Geocoding now works the way it should. I'm not sure if the required_info method is working though. Here's my model in it's current state: http://pastie.org/872455 Thanks for your help.
Post the pastie link to your migration script. I will see if I can reproduce your issue.
KandadaBoggu
Here's my schema: http://pastie.org/872777Here's my all off my migrations in one pastie: http://pastie.org/872799
I disabled the `lag_list` check( as I didn't have the gem) and I got valid errors while running your code. Have you tried to test your model from `script/console`? Check the behavior when all `validators` except `required_info` is commented out.
KandadaBoggu
Here's the script/console print out: http://pastie.org/872987It just let's me create new entries without errors, just like in the view. This is with the validates_presence_of and the before_save commented out.
The validation is done during calls `save` or `valid?`. There is no validation during a `new` call. Execute these additional commands: `e.valid?` and `e.errors.to_xml`. Post a link to the results.
KandadaBoggu
It looks like the error message is reaching the console, it's just not reaching the view. Here's the pastie: http://pastie.org/873076 I'm kind of confused.
That is quite unlikely. Its quite possible that you are not displaying the errors in your views. Check the database to see if the record was saved in the DB. Post a link to your view.
KandadaBoggu
The entry was not created from the script/console interaction. entry#new: http://pastie.org/873126 entry#show just shows the _entry.html.erb partial: http://pastie.org/873128
Even the view might not create the entry. Go to the `script/console` and type `Entry.last` and see if the entry was saved. Your view code looks fine. I guess the issue might be in your controller code. Post the controller code for review.
KandadaBoggu
The script/console's result was an entry that I added awhile ago, before anything we've done here. My entries controller: http://pastie.org/873249 Seriously, thanks again for your help. I really appreciate it.
I found the issue and fixed it. I have updated my answer with the fix and added a description of the problem. Best of luck and take care.
KandadaBoggu
I can't thank you enough KandadaBoggu. Thank you. That works perfectly. I'm currently an Emacs user, but I've used Netbeans in the past. I will familiarize myself with it's debugger. Thank you and I hope you have an awesome day, you sure made mine :)