# Using update\_attributes(params\[:something\]) w/ manual assignment

**URL:** <https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325>\
**Category:** rubyonrails-talk\
**Created:** [June 9, 2009, 8:18pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325 "2009-06-09T20:18:13Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Phoenix\_Rising](https://avatars.discourse-cdn.com/v4/letter/p/e68b1a/32.png) [@Phoenix\_Rising](https://discuss.rubyonrails.org/u/Phoenix_Rising)\
**Post date:** [June 9, 2009, 8:18pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/1 "2009-06-09T20:18:13Z")

</div>

So far this appears to be working, but it looks kind of jacked up. I'm concerned that I could be opening myself up to a hole in the future (security or portability) by doing what I've outlined below. Are there any better ways to go about doing this WITHOUT calling save more than once?

Here's an example:

---

<div class="post-metadata">

**Author:** ![11175](https://avatars.discourse-cdn.com/v4/letter/1/8edcca/32.png) [@11175](https://discuss.rubyonrails.org/u/11175)\
**Post date:** [June 9, 2009, 9:05pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/2 "2009-06-09T21:05:16Z")

</div>

I don't see the "multiple" calls to save.

update\_attributes will call save but I don't see the other call to save.

By the way, update\_attributes calls save (as of 2.3.2? or was it before that) only if at least one attribute has changed.

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [June 9, 2009, 9:44pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/3 "2009-06-09T21:44:32Z")

</div>

Actually it's save which is a no-op if no attributes has saved (this was part of 2.1).

you can do @car.attributes = params[:car] which will do all the attribute setting that update\_attributes does but doesn't call save. If you are (and rightly so) worried about what users submitting attributes you don't want them to, take a look at attr\_protected/ attr\_accessible

Fred

---

<div class="post-metadata">

**Author:** ![Phoenix\_Rising](https://avatars.discourse-cdn.com/v4/letter/p/e68b1a/32.png) [@Phoenix\_Rising](https://discuss.rubyonrails.org/u/Phoenix_Rising)\
**Post date:** [June 9, 2009, 9:51pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/4 "2009-06-09T21:51:56Z")

</div>

Hey Perry,

Thanks for the reply. As for multiple calls to save, I don't have that in my example (because I'm not doing it). What I meant was that, say instead of calling update\_attributes, I called save right after the manual assignment, then called update\_attributes again to update attributes from the params hash.

And that's just what concerns me - I guess I'm just not sure how update\_attributes works. From the Rails framework documentation:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# File vendor/rails/activerecord/lib/active\_record/base.rb, line 2619 2619: def update\_attributes(attributes) 2620: self.attributes = attributes 2621: save 2622: end

What I don't "get" is how self.attributes = attributes works. Obviously it's assigning based on the passed-in parameters hash, but given in my example that hash did NOT contain "condition" or "value", it seems to skip those and go with whatever the current values are. And as far as I know, this has been standard with update\_attributes from day one.

So - and somebody please verify or correct my understanding - as long as the hash I pass in to update\_attributes doesn't overwrite my prior manual assignment methods, this functionality should continue - through future updates to the framework - to work as expected - correct?

And if the above is correct, does anybody see anything else wrong that I may not have considered with doing things this way?

Thanks again =)

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [June 9, 2009, 10:24pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/5 "2009-06-09T22:24:36Z")

</div>

> ```
> \# File vendor/rails/activerecord/lib/active\_record/base\.rb, line
> 
> ```
> 
> 2619 2619: def update\_attributes(attributes) 2620: self.attributes = attributes 2621: save 2622: end
> 
> What I don't "get" is how self.attributes = attributes works.

The attributes= method is badly named, since it's not actually an assignment. A better name would be merge\_attributes. The implementation is basically

new\_attributes.each do |key, value| &nbsp;&nbsp;send(key + '=', value) end

Fred

---

<div class="post-metadata">

**Author:** ![Phoenix\_Rising](https://avatars.discourse-cdn.com/v4/letter/p/e68b1a/32.png) [@Phoenix\_Rising](https://discuss.rubyonrails.org/u/Phoenix_Rising)\
**Post date:** [June 10, 2009, 3:35pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/6 "2009-06-10T15:35:30Z")

</div>

Wow, thanks for such great feedback Perry and Fred! You both hit the point from multiple angles, all of which are important. Thank you both very much for your help!

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 27, 2010, 9:55pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/7 "2010-05-27T21:55:51Z")

</div>

Perry Smith wrote:

> By the way, update\_attributes calls save (as of 2.3.2? or was it before that) only if at least one attribute has changed.

It appears to me that this is not true. I tried it below using 2.3.5. As you can see the 'locale' attribute was "es" and it got updated to "es" anyway. Did I get this wrong?

> > Language.first

&nbsp;&nbsp;Language Load (0.8ms) SELECT \* FROM `languages` LIMIT 1

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 27, 2010, 10:28pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/8 "2010-05-27T22:28:09Z")

</div>

Jose Ambros-ingerson wrote:

> Perry Smith wrote:
> 
> > By the way, update\_attributes calls save (as of 2.3.2? or was it before that) only if at least one attribute has changed.

Though failure to behave this way (see above) is hurting me; I have an observer that get's triggered on the save, but if the save didn't change anything (the record attributes are the same as before the save) I would of preferred that the observer had not been triggered.

Is writing a custom update\_attributes (that does a save only if it would result in different attribute values) the way to go?

THanks in advance for your help, Jose

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 27, 2010, 10:38pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/9 "2010-05-27T22:38:02Z")

</div>

Jose Ambros-ingerson wrote:

> Jose Ambros-ingerson wrote:
> 
> > Perry Smith wrote:
> > 
> > > By the way, update\_attributes calls save (as of 2.3.2? or was it before that) only if at least one attribute has changed.
> 
> Though failure to behave this way (see above) is hurting me; I have an observer that get's triggered on the save, but if the save didn't change anything (the record attributes are the same as before the save) I would of preferred that the observer had not been triggered.
> 
> Is writing a custom update\_attributes (that does a save only if it would result in different attribute values) the way to go?
> 
> THanks in advance for your help, Jose

I suggest looking at

> **[\#109 Tracking Attribute Changes - RailsCasts](http://railscasts.com/episodes/109-tracking-attribute-changes)**
>
> Short Ruby on Rails screencasts containing tips, tricks and tutorials. Great for both novice and experienced web developers.

It gives you an overview of how it is suppose to work. It seems like you should be able to test the model to see if it thinks a particular value has been changed or not and hopefully figure out what is going on.

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [May 28, 2010, 6:55am UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/10 "2010-05-28T06:55:13Z")

</div>

Actually that bit in the logs show the name getting set to spanish as well. It's also possible that you've turned off this behaviour - ActiveRecord::Base.partial\_updates (or something along those lines) controls whether this is enabled if my memory is correct

Fred

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 28, 2010, 8:33pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/11 "2010-05-28T20:33:12Z")

</div>

Frederick Cheung wrote:

> Actually that bit in the logs show the name getting set to spanish as well. It's also possible that you've turned off this behaviour - ActiveRecord::Base.partial\_updates (or something along those lines) controls whether this is enabled if my memory is correct
> 
> Fred

THanks Fred and Perry for your replies. I followed up on your suggestions yet I have not been able to make it work as advertised. As shown in the example below I've made sure that ActiveRecord::Base.partial\_updates is true (as indicated by Fred and in the Railscasts episode) and tried it in my dev machine and in the production server with the same result (both running 2.3.5). Any ideas on how to make it work? does it work for you?

Thanks in advance, Jose

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 28, 2010, 8:46pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/12 "2010-05-28T20:46:29Z")

</div>

Jose Ambros-ingerson wrote:

> Frederick Cheung wrote:
> 
> > Actually that bit in the logs show the name getting set to spanish as well. It's also possible that you've turned off this behaviour - ActiveRecord::Base.partial\_updates (or something along those lines) controls whether this is enabled if my memory is correct
> > 
> > Fred
> 
> THanks Fred and Perry for your replies. I followed up on your suggestions yet I have not been able to make it work as advertised. As shown in the example below I've made sure that ActiveRecord::Base.partial\_updates is true (as indicated by Fred and in the Railscasts episode) and tried it in my dev machine and in the production server with the same result (both running 2.3.5). Any ideas on how to make it work? does it work for you?
> 
> Thanks in advance, Jose
> 
> ------------------- $ ./script/console Loading production environment (Rails 2.3.5)
> 
> ?\> ActiveRecord::Base.partial\_updates =\> true
> 
> > > Language.first
> 
> &nbsp;&nbsp;Language Load (0.2ms) SELECT \* FROM `languages` LIMIT 1 =\> #\<Language id: 1, name: "spanish", locale: "es"\>
> 
> > > Language.first.update\_attributes({:locale=\>"es"})
> 
> &nbsp;&nbsp;Language Load (0.2ms) SELECT \* FROM `languages` LIMIT 1 &nbsp;&nbsp;SQL (0.1ms) BEGIN &nbsp;&nbsp;Language Update (0.4ms) UPDATE `languages` SET `name` = 'spanish', `locale` = 'es' WHERE `id` = 1 &nbsp;&nbsp;SQL (0.2ms) COMMIT =\> true

I've not looked / tested on 2.3.5 but it was working in 2.3.4 for me.

I was hoping you would do something like:

a = Language.first puts a.locale a.update\_attributes({:local =\> 'es'})

I'm not sure with all the "lazy" execution stuff what Language.first is doing. The select you are seeing may be after the check to see if the record is dirty or not.

Also, I can't remember the names of the methods but there is a way to ask if a.locale has been modified. I would also experiment with a.save and see if it saves it or not. Last, you might have something like a plugin that has hooked in to update\_attributes.

Also, perhaps your "es" is not equal to the "es" in the database? You might experiment with:

a = Language.first b = a.locale a.locale = b a.save

That should not save anything. Also, you can ask if a.locale has changed after setting it to b. Last, you can set a.locale to "es" and then ask if it has changed. Maybe before a.locale is utf8 and after it is ascii?

Not sure if this helps or not.

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 28, 2010, 9:01pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/13 "2010-05-28T21:01:44Z")

</div>

Perry Smith wrote:

> Jose Ambros-ingerson wrote:
> 
> > Frederick Cheung wrote:

> > THanks Fred and Perry for your replies. I followed up on your suggestions yet I have not been able to make it work as advertised. As shown in the example below I've made sure that ActiveRecord::Base.partial\_updates is true (as indicated by Fred and in the Railscasts episode) and tried it in my dev machine and in the production server with the same result (both running 2.3.5). Any ideas on how to make it work? does it work for you?
> > 
> > Thanks in advance, Jose
> > 
> > ------------------- $ ./script/console Loading production environment (Rails 2.3.5)
> > 
> > ?\> ActiveRecord::Base.partial\_updates =\> true
> > 
> > > > Language.first
> > 
> > &nbsp;&nbsp;Language Load (0.2ms) SELECT \* FROM `languages` LIMIT 1 =\> #\<Language id: 1, name: "spanish", locale: "es"\>
> > 
> > > > Language.first.update\_attributes({:locale=\>"es"})
> > 
> > &nbsp;&nbsp;Language Load (0.2ms) SELECT \* FROM `languages` LIMIT 1 &nbsp;&nbsp;SQL (0.1ms) BEGIN &nbsp;&nbsp;Language Update (0.4ms) UPDATE `languages` SET `name` = 'spanish', `locale` = 'es' WHERE `id` = 1 &nbsp;&nbsp;SQL (0.2ms) COMMIT =\> true
> 
> I've not looked / tested on 2.3.5 but it was working in 2.3.4 for me.
> 
> I was hoping you would do something like:
> 
> a = Language.first puts a.locale a.update\_attributes({:local =\> 'es'})
> 
> I'm not sure with all the "lazy" execution stuff what Language.first is doing. The select you are seeing may be after the check to see if the record is dirty or not.
> 
> Also, I can't remember the names of the methods but there is a way to ask if a.locale has been modified. I would also experiment with a.save and see if it saves it or not. Last, you might have something like a plugin that has hooked in to update\_attributes.
> 
> Also, perhaps your "es" is not equal to the "es" in the database? You might experiment with:
> 
> a = Language.first b = a.locale a.locale = b a.save
> 
> That should not save anything. Also, you can ask if a.locale has changed after setting it to b. Last, you can set a.locale to "es" and then ask if it has changed. Maybe before a.locale is utf8 and after it is ascii?
> 
> Not sure if this helps or not.

Hi Perry, Tried your suggestion;

> > a = Language.first

&nbsp;&nbsp;Language Load (0.4ms) SELECT \* FROM `languages` LIMIT 1

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 28, 2010, 9:05pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/14 "2010-05-28T21:05:42Z")

</div>

In fact, I just tried the most simple case and I see an mySQL update

> > a = Language.first

&nbsp;&nbsp;Language Load (0.5ms) SELECT \* FROM `languages` LIMIT 1

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [May 28, 2010, 9:07pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/15 "2010-05-28T21:07:43Z")

</div>

> So I guess this rules out all but a some plugin interference; I'll look into it; Do you know of a good way to do this?

What database are you using? Maybe this feature is just for some of the databases but not all? (That wouldn't make much sense to me but its a thought.)

It seems like you could add in a validation for locale (for example) and when it is called, just raise an exception. Then look at the stack (and look at the code for each of the routines in the stack) to see why you got down as far as you did.

Maybe someone else will chip in with some suggestions too.

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [June 2, 2010, 6:50pm UTC](https://discuss.rubyonrails.org/t/using-update-attributes-params-something-w-manual-assignment/43325/16 "2010-06-02T18:50:07Z")

</div>

Perry Smith wrote:

> > So I guess this rules out all but a some plugin interference; I'll look into it;

I finally was able to figure out what was going on. It was interference from the be9-acl9 gem which is based on acl9 with some SQL query generation improvements (as of v 0.11) The partial\_updates problem was present in acl9's v0.11 but has been fixed in v 0.12 which I will be using now.

Thanks to everyone for your help with this issue.

Jose
