Hi,
Why does ActiveRecord allow perception of success when updating an ID,
however it doesn’t really work(i.e. no change in database)?
Here’s an example. The update of “id” versus update of a non-existent
attribute.
?> ai = AccountItem.find(:first) => #<AccountItem id: 1, account_id: 1,
date: “2009-01-11”, amount: #BigDecimal:22fb334,‘0.1E2’,4(8), balance:
#BigDecimal:22fb1f4,‘0.0’,4(8), description: “test”, notes: nil,
created_at: “2009-01-11 09:47:28”, updated_at: “2009-01-11 09:47:28”> >>
ai.update_attributes!(:id => 99999) => true # SEEMS TO INDICATE IT
WORKED >>
AccountItem.find(:all) => [#<AccountItem id: 1, account_id: 1, date:
“2009-01-11”, amount: #BigDecimal:22f27c0,‘0.1E2’,4(8), balance:
#BigDecimal:22f2680,‘0.0’,4(8), description: “test”, notes: nil,
created_at: “2009-01-11 09:47:28”, updated_at: “2009-01-11 09:47:28”>] #
IT
DIDN’T AS THE ID IS STILL 1 >>
?> ai.update_attributes!(:XXXX => 99999) NoMethodError: undefined method XXXX=' for #<AccountItem:0x22fc6a8> <== THIS IS A BIT MORE LIKE YOU WOULD EXPECT from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/attribute_methods.rb:251:inmethod_missing’ from
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:2372:in send' from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:2372:inattributes=’ from
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:2371:in each' from /opt/local/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:2371:inattributes=’ from
/opt/local/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:2278:in
`update_attributes!’ from (irb):60 >>
Why does ActiveRecord allow perception of success when updating an ID,
however it doesn’t really work(i.e. no change in database)?
That is because :id is a special case and is protected from mass
assignment.
The reason it “works” or says that it does is because when you submit
an update form, you might have a params hash that looks like:
params[:account] #=> {:id => 2, :name => “Bob”}
and you will then do:
a = Account.find(params[:account][:id])
a.update_attributes(params[:account])
Now… in 99% of cases, you want this update_attributes command to
work, but you definately do NOT want some smartarse out there sending
in a carefully crafted web request that changes the ID value of the
account!
So that’s why, update_attributes “silently” ignores any attribute that
is protected from mass assignment.
Actually… it doesn’t ignore it. Look in your logs and you will see
something along the lines of “Can’t mass assign protected attribute
:id” or something.
PS. Just noted the other methods also don’t work fyi - see below. That
is
it doesn’t seem to be mass assignment related.
?> ai = AccountItem.find(:first)
=> #<AccountItem id: 1, account_id: 1, date: “2009-01-11”, amount:
#BigDecimal:22e80b8,‘0.1E2’,4(8), balance:
#BigDecimal:22e7f78,‘0.0’,4(8), description: “test”, notes: nil,
created_at: “2009-01-11 09:47:28”, updated_at: “2009-01-11 09:47:28”>
thanks - given all of this what do you think about the fact Rails
doesn’t
highlight the issue via exception? It still seems misleading to me the
way
it works…