Ailison Carvalho
Ailison Carvalho

Reputation: 123

Rails 3: Validate association and show perfectly the validation to the user

Fist, I'm using rails 3.0.9 and ruby 1.8.7. I need some help because I couldn't validate and show it perfectly to my user on screen.

The model:

class Book < ActiveRecord::Base
    belongs_to :genre
    validates_presence_of :title, :genre
    attr_accessible :genre_id
end

The Form:

<div class="field">
    <%= f.label :genre %><br />
    <%= f.collection_select(:genre_id, Genre.all(:order => :name), :id, :name, :prompt => 'Select') %>
</div>

When I send the form in blank (with the prompt value selectioned by default) the error message appears perfectly "Genre can't be blank" but in the form I receive the html like:

<div class="field">
    <div class="field_with_errors">
        <label for="book_genre">Genre</label>
    </div>
    <br>
    <select name="book[genre_id]" id="book_genre_id">
        <option value="">Select</option>
        <option value="2">Gramatic</option>
        <option value="1">Terror</option>
    </select>
</div>

I need the select field inside the div.field_with_erros too because the red background that I defined in CSS.

After that I tried change the f.collection_select :genre_id to :genre

Now I got the select field inside the div.field_with_erros. Owwww yeahhh a victory, for a few moments, until I realize that the validation always accuse error, the rails don't know that the select field :genre is :genre_id that it looks for.

My question is: How to make the :genre change to :genre_id in validation? Or you all guys have a better way to do it?

Keep going in tests I tried change the label and the collection_select to genre_id and the validation works perfectly but without generate the html with the div.field_with_errors so I tried to put the :genre_id in the validates_presence_of so now it look like: "validates_presence_of :title, :genre, :genre_id".

Great, but...

  1. When I submit the form and had select the default prompt value the validation works fine but they accuse 2 errors, one to :genre and another to :genre_id (¬¬) but the html is fine, the label and the select is inside the div.field_with_erros.

  2. If I submit the form and had select some value from the genres the validation and the html is ok.

  3. If I submit the form but I had change the value of some option to one invalid to test if the validation between models works the validation really works fine but the html doesn't created the div.field_with_erros.

Anyone could help me, please? (Yes, my english isn't the best. Sorry!)

Upvotes: 5

Views: 575

Answers (2)

Artem P
Artem P

Reputation: 5332

I didn't found any way that solves this problem and decided to just check for error in view:

<% if f.object.errors.include?(:genre) %>
  <div class='field_with_errors'> 
<% end %>
// :genre field
<% if f.object.errors.include?(:genre) %>
  </div> 
<% end %>

Some links:

  1. http://railsguides.net/belongs-to-and-presence-validation-rule1/ why to not validate presence of id but association itself.
  2. https://github.com/frank-west-iii/association_validations difference in validating on id or association.
  3. http://iada.nl/blog/article/rails-tip-display-association-validation-errors-fields hijack Rails method

Upvotes: 1

Chris Lewis
Chris Lewis

Reputation: 1325

I've created some scaffolded models to test this. I setup 2 migrations:

class CreateGenres < ActiveRecord::Migration
  def change
    create_table :genres do |t|
      t.string :title
      t.timestamps
    end
  end
end

class CreateBooks < ActiveRecord::Migration
  def change
    create_table :books do |t|
      t.string :name
      t.references :genre
      t.timestamps
    end
  end
end

in the form I have:

<%= f.label :genre_id %>
<%= f.collection_select(:genre_id, Genre.all(:order => :title), :id, :title, :prompt => 'Select') %>

And in the models I have:

class Genre < ActiveRecord::Base
  attr_accessible :title
  has_many :books
end

class Book < ActiveRecord::Base
  belongs_to :genre
  validates_presence_of :name, :genre_id
  attr_accessible :name, :genre_id
end

The validation then works as I would expect ...

Upvotes: 1

Related Questions