Phoenix Rising
2009-Jun-09 20:18 UTC
Using update_attributes(params[:something]) w/ manual assignment
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: ------------------------------- POST data: {car => {"make" => "Pontiac", "model" => "GTO", "year" => "2004"}} car_controller.rb ------------------------ def edit @car = Car.find(:first, :conditions => {:id => params[:id]}) @car.condition = "Good" @car.value = "$24,924" # Totally hypothetical if @car.update_attributes(params[:car]) flash[:notice] = "Car updated successfully." redirect_to :action => view, :id => @car.id else flash[:warning] = "There was a problem updating your entry." end end ----------- As you can see in this example, I''m manually assigning values to an object inherited from ActiveRecord BEFORE calling update_attributes. What concerns me is that I''m passing in the hash from POST to update_attributes, and while it seems to work just fine and I''m receiving no deprecation warnings, I''m curious: is there a better way to do this without calling save multiple times? I have a callback after save that sends out e-mail, so that''s why I don''t want multiple saves (no sense in 2-3 emails for each edit). Thanks for your help =)
Perry Smith
2009-Jun-09 21:05 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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. -- Posted via http://www.ruby-forum.com/.
Frederick Cheung
2009-Jun-09 21:44 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
On Jun 9, 10:05 pm, Perry Smith <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> 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.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
Phoenix Rising
2009-Jun-09 21:51 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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: # 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 =) On Jun 9, 3:05 pm, Perry Smith <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> 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. > -- > Posted viahttp://www.ruby-forum.com/.
Frederick Cheung
2009-Jun-09 22:24 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
On Jun 9, 10:51 pm, Phoenix Rising <PolarisRis...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > # 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| send(key + ''='', value) end Fred> 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 =) > > On Jun 9, 3:05 pm, Perry Smith <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> > wrote: > > > 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. > > -- > > Posted viahttp://www.ruby-forum.com/.
Phoenix Rising
2009-Jun-10 15:35 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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! On Jun 9, 6:02 pm, Perry Smith <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Phoenix Rising wrote: > > 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? > > I believe that is a safe assumption. I think Fred (two posts up) has a > valid point but may not be what you are worried about right now. > > Usually, what I do is merge the added options in and then call > update_attributes. Forgive the syntax but something like > > new_options = params[:car].merge({ > :condition => "Good", > :value => "$24,924" > }) > > @car.update_attributes(new_options) > > The general gist is (and I think you already know this): > 1) setting @car.xyz = 5 does not do a save > 2) update_attributes could blow away previous sets if it contains the > same attribute > 3) attributes not in the hash passed to update_attributes are not > altered (how could they?) > > As far as "idioms", your style you will not see in Ruby code as often as > some form of merging the options and then calling update_attributes. It > is a bit slower that way but Ruby programmers seem to want clarity over > a tiny bit if performance. > -- > Posted viahttp://www.ruby-forum.com/.
Jose Ambros-ingerson
2010-May-27 21:55 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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.firstLanguage Load (0.8ms) SELECT * FROM `languages` LIMIT 1 +----+---------+--------+ | id | name | locale | +----+---------+--------+ | 1 | Español | es | +----+---------+--------+ 1 row in set>> Language.first.update_attributes({:locale=>"es"})Language Load (0.4ms) SELECT * FROM `languages` LIMIT 1 SQL (0.1ms) BEGIN Language Update (0.3ms) UPDATE `languages` SET `name` = ''spanish'', `locale` = ''es'' WHERE `id` = 1 SQL (1.2ms) COMMIT => true -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Jose Ambros-ingerson
2010-May-27 22:28 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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 -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Perry Smith
2010-May-27 22:38 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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, JoseI suggest looking at http://railscasts.com/episodes/109-tracking-attribute-changes 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. -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Frederick Cheung
2010-May-28 06:55 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
On May 27, 10:55 pm, Jose Ambros-ingerson <li...-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> 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. > > 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?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 -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Jose Ambros-ingerson
2010-May-28 20:33 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
Frederick Cheung wrote:> On May 27, 10:55�pm, Jose Ambros-ingerson <li...-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> > 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 > > FredTHanks 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.firstLanguage Load (0.2ms) SELECT * FROM `languages` LIMIT 1 => #<Language id: 1, name: "spanish", locale: "es">>> Language.first.update_attributes({:locale=>"es"})Language Load (0.2ms) SELECT * FROM `languages` LIMIT 1 SQL (0.1ms) BEGIN Language Update (0.4ms) UPDATE `languages` SET `name` = ''spanish'', `locale` = ''es'' WHERE `id` = 1 SQL (0.2ms) COMMIT => true -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Perry Smith
2010-May-28 20:46 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
Jose Ambros-ingerson wrote:> Frederick Cheung wrote: >> On May 27, 10:55�pm, Jose Ambros-ingerson <li...-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> >> 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 > Language Load (0.2ms) SELECT * FROM `languages` LIMIT 1 > => #<Language id: 1, name: "spanish", locale: "es"> >>> Language.first.update_attributes({:locale=>"es"}) > Language Load (0.2ms) SELECT * FROM `languages` LIMIT 1 > SQL (0.1ms) BEGIN > Language Update (0.4ms) UPDATE `languages` SET `name` = ''spanish'', > `locale` = ''es'' WHERE `id` = 1 > SQL (0.2ms) COMMIT > => trueI''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. -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Jose Ambros-ingerson
2010-May-28 21:01 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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 >> Language Load (0.2ms) SELECT * FROM `languages` LIMIT 1 >> => #<Language id: 1, name: "spanish", locale: "es"> >>>> Language.first.update_attributes({:locale=>"es"}) >> Language Load (0.2ms) SELECT * FROM `languages` LIMIT 1 >> SQL (0.1ms) BEGIN >> Language Update (0.4ms) UPDATE `languages` SET `name` = ''spanish'', >> `locale` = ''es'' WHERE `id` = 1 >> 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.firstLanguage Load (0.4ms) SELECT * FROM `languages` LIMIT 1 +----+---------+--------+ | id | name | locale | +----+---------+--------+ | 1 | Español | es | +----+---------+--------+ 1 row in set>> b =a.locale=> "es">> a.locale = b=> "es">> a.changed?=> false>> a.saveSQL (0.2ms) BEGIN Language Update (0.6ms) UPDATE `languages` SET `name` = ''spanish'', `locale` = ''es'' WHERE `id` = 1 SQL (0.5ms) COMMIT => true 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? Thanks again, Jose -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Jose Ambros-ingerson
2010-May-28 21:05 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
In fact, I just tried the most simple case and I see an mySQL update>> a = Language.firstLanguage Load (0.5ms) SELECT * FROM `languages` LIMIT 1 +----+---------+--------+ | id | name | locale | +----+---------+--------+ | 1 | Español | es | +----+---------+--------+ 1 row in set>> a.saveSQL (0.2ms) BEGIN Language Update (0.4ms) UPDATE `languages` SET `name` = ''spanish'', `locale` = ''es'' WHERE `id` = 1 SQL (0.5ms) COMMIT => true -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Perry Smith
2010-May-28 21:07 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
> 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. -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Jose Ambros-ingerson
2010-Jun-02 18:50 UTC
Re: Using update_attributes(params[:something]) w/ manual assignment
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 -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.