SimpleForm does not show "presence" validation error on association

3,840 views
Skip to first unread message

mcbsys

unread,
Aug 31, 2012, 3:39:02 PM8/31/12
to plataformate...@googlegroups.com
Hi,

I'm using Rails 3.2.3 with SimpleForm 2.0.1 and Twitter Bootstrap.

My Message model has a required association with to_contact:

class Message < ActiveRecord::Base
  belongs_to :to_contact,    :class_name => "Contact", :inverse_of => :to_contact_messages
  validates :to_contact,      :presence => true
end

I used SimpleForm to create a select list of contacts:

            <%= f.input :to_contact_id, :required => true,
            :collection => @message.account.contacts.order(:last_name, :first_name),
            :value_method => :id, :label_method => :display_name,
            :input_html => { :class => "input-large" } %>

If I leave the select box blank and submit the form, SimpleForm does not apply the "error" formatting and error message to the field. However if I examine object.errors.full_messages, I see that Rails did detect the validation error; it says "To contact can't be blank".

If I change the model to validate the to_contact_id field instead of the association (to_contact), SimpleForm applies the "error" formatting correctly:

  validates :to_contact_id,      :presence => true

I was under the impression that when writing the validation for the association, I should only reference the association, not the id (see for example http://stackoverflow.com/a/3755844/550712). Is SimpleForm supposed to display the error message either way? Is it okay to validate to_contact_id instead of to_contact?

Thanks,

Mark

mcbsys

unread,
Aug 31, 2012, 6:09:30 PM8/31/12
to plataformate...@googlegroups.com
I've been digging in to whether I need to validate to_contact or to_contact_id. It seems that by validating to_contact, it will confirm that the Contact record is there. It's pretty confusing especially since it seems to behave exactly the opposite of the way it is documented in the Rails Guide. See my comment on this answer:  http://stackoverflow.com/a/11327575/550712.

Vasiliy Ermolovich

unread,
Aug 31, 2012, 10:27:08 PM8/31/12
to plataformate...@googlegroups.com
Hi. For proper association validation you should use validates :to_contact, :presence => true together with f.association :to_contact

mcbsys

unread,
Sep 1, 2012, 1:49:48 PM9/1/12
to plataformate...@googlegroups.com
Interesting that you also disagree with Rails Guide, which says you have to validate presence of to_contact_id, not to_contact.

Validating presence of to_contact does seem better since it checks if the record is there. Unfortunately in this case, SimpleForm will not wrap the missing To-contact field with the error markup. It seems I have to do this:

# confirm to_contact_id is filled in (and mark form if it is not):

validates :to_contact_id, :presence => true


# confirm associated record is found (will not mark form if it is not):

validates :to_contact, :presence => true

# confirm associated record is valid? (probably will not mark form if it is not):
validates :to_contact, :associated => true

Is there some way to get SimpleForm to wrap the to_contact_id field with an error if the to_contact validation fails? I am trying to avoid also displaying full_messages since usually that is redundant to the fields marked with errors.

Carlos Antonio da Silva

unread,
Sep 6, 2012, 8:29:47 PM9/6/12
to plataformate...@googlegroups.com
Here's how it works with SimpleForm:

If you want to mark an attribute (whichever one), you have to use the presence validation on it. So for instance, if you use:

    validates :to_contact_id, presence: true

SimpleForm's f.input method will work with

    f.input :to_contact_id ...


However, if you're dealing with an association and use:

    f.association :to_contact

SimpleForm will try to be smarter and search for errors in both :to_contact_id and :to_contact, so it doesn't matter whether you validate the presence of one or another. But this doesn't happen with f.input, even though the input is related to an association.


So, in short: with f.input, use the attribute name so that SimpleForm will use the presence validation, or use f.association and validate whichever you want: the attribute or the association name.

Hope that helps!
--
At.
Carlos Antonio

mcbsys

unread,
Sep 8, 2012, 6:08:45 PM9/8/12
to plataformate...@googlegroups.com
Thanks Carlos. That's an interesting difference between f.input and f.association. Besides the "smarter" validation, is there any reason to use f.association? I still need to specify collection, value_method, and label_method, right?

      <%= f.association :to_contact, :required => true,

              :collection => @message.account.contacts.order(:last_name, :first_name),
              :value_method => :id, :label_method => :display_name,
              :input_html => { :class => "input-large" } %>

Carlos Antonio da Silva

unread,
Sep 8, 2012, 6:17:36 PM9/8/12
to plataformate...@googlegroups.com
The collection is automatically inferred from the association if possible, unless you need to add some specific condition (as apparently you need some specific ordering). And it generates a select by default (which also happens if you give a :collection to f.input).

Other than that and the validations/errors logic we commented previously, there's nothing that makes them much different, in fact, f.association ends up calling f.input at the end, after doing some association inferring as I said, and you can see everything here: https://github.com/plataformatec/simple_form/blob/master/lib/simple_form/form_builder.rb#L166

Cheers.

--
At.
Carlos Antonio

mcbsys

unread,
Sep 8, 2012, 6:51:46 PM9/8/12
to plataformate...@googlegroups.com
Excellent, thanks very much. Yes I need special ordering plus I only want to show contacts in the associated account, not in all accounts. In fact, I should probably add CanCan's "accessible_by(current_ability, :read)" to the scope just to make sure the user is in fact allowed to read the contacts.

Nonetheless, just having it named "f.association" is helpful in that it makes it more obvious that the data is coming from an associated table, not the main table.

Carlos Antonio da Silva

unread,
Sep 8, 2012, 7:41:52 PM9/8/12
to plataformate...@googlegroups.com
No problem, glad I could help :).
--
At.
Carlos Antonio
Reply all
Reply to author
Forward
0 new messages