Parent model running validations on all existing children

In my application, a Language has many Phrases. Here is my code:

#language model
has_many :phrases
accepts_nested_attributes_for :phrases

#phrase model
validates_presence_of :value
belongs_to :language

#languages controller
def edit
@language = Language.find(params[:id])

Let’s say we only want to update some of the phrases (e.g. by

category, date, etc)
@phrases = @language.phrases.all(:limit => 3)
end

def update
@language = Language.find(params[:id])
if @language.update_attributes(params[:language])
flash[:notice] = “Successfully updated language.”
redirect_to edit_language_path(@language)
else
render :action => ‘edit’
end
end

project edit view

<% form_for @language do |f| %>
<%= f.error_messages %>

<%= f.label :name %>
<%= f.text_field :name %>

<% f.fields_for :phrases, @phrases do |phrases_form| %>

<%= phrases_form.label :value %> <%= phrases_form.text_field :value %>

<% end %>

<%= f.submit %>

<% end %>

When I submit the form, if at least one of the phrases being saved is
an existing record, every single phrase corresponding to @language
will be validated, instead of running validations only in the three
phrases being updated. That problem isn’t present when all of the
phrases being saved are new records.

I was expecting Rails to only validate the phrase that is being updated,
here you can see it’s validating all of the existing phrases:

$ script/console
Loading development environment (Rails 2.3.5)

lang = Language.first
=> #<Language id: 1, name: “Italiano”>

lang.phrases
=> [#<Phrase id: 7, value: “Buona notte”, language_id: 1>,
#<Phrase id: 10, value: “Ciao”, language_id: 1>,
#<Phrase id: 11, value: “Prego”, language_id: 1>]

lang.phrases_attributes = [{:id => “7”, :value => “Buon giorno”}]
=> [{:value=>“Buon giorno”, :id=>“7”}]

lang.save

Validating: Buon giorno

Validating: Ciao

Validating: Prego

=> true

My models, again, now with the added “before_validation” callback:

class Language < ActiveRecord::Base
has_many :phrases
accepts_nested_attributes_for :phrases
end

class Phrase < ActiveRecord::Base
validates_presence_of :value
belongs_to :language
def before_validation
logger.debug “\nValidating: #{self.value}\n”
end
end

Validating all phrases is a real problem in my app, as I have tens of
thousands; Is there a way to avoid this? Is this normal behavior for
Rails?

Ruben Ascencio wrote:

In my application, a Language has many Phrases. Here is my code:

#language model
has_many :phrases
accepts_nested_attributes_for :phrases

#phrase model
validates_presence_of :value
belongs_to :language

#languages controller
def edit
@language = Language.find(params[:id])

Let’s say we only want to update some of the phrases (e.g. by

category, date, etc)
@phrases = @language.phrases.all(:limit => 3)
end

def update
@language = Language.find(params[:id])
if @language.update_attributes(params[:language])
flash[:notice] = “Successfully updated language.”
redirect_to edit_language_path(@language)
else
render :action => ‘edit’
end
end

project edit view

<% form_for @language do |f| %>
<%= f.error_messages %>

<%= f.label :name %>
<%= f.text_field :name %>

<% f.fields_for :phrases, @phrases do |phrases_form| %>

<%= phrases_form.label :value %> <%= phrases_form.text_field :value %>

<% end %>

<%= f.submit %>

<% end %>

When I submit the form, if at least one of the phrases being saved is
an existing record, every single phrase corresponding to @language
will be validated, instead of running validations only in the three
phrases being updated. That problem isn’t present when all of the
phrases being saved are new records.