What exception should I be looking for when I rescue a save. So I have currently begin obj.save redirect_to :action => ''some_action'' rescue redirect_to :action => ''another_action'' end This works fine but it captures all exceptions even those not related to validation errors. I want to only capture exceptions when there is some validation error. If there is some other exception thrown (bug in Rails, bug in my data objects, etc) then I want it thrown in that page with the standard Rails debugging info outputted (stack trace, etc.). But currently if I get some sort of error it redirects to my "failed" page because I am catching all exceptions. So what is the proper exception type I should be catching? Eric _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Validation errors don''t throw an exception, they just return false. Again i recommend following idiom: def index @obj = Obj.new @params[''obj''] if @request.post? and @obj.save redirect_to :action => ''some_action'' end end Just let the form post to itself until validation works out and a redirect will occur. Exceptions can be handled in the rescue_action_in_public hook: http://api.rubyonrails.org/classes/ActionController/Rescue.html On Sun, 23 Jan 2005 13:21:11 -0500, Eric Anderson <eric-ANzg6odk14w@public.gmane.org> wrote:> What exception should I be looking for when I rescue a save. So I have > currently > > begin > obj.save > redirect_to :action => ''some_action'' > rescue > redirect_to :action => ''another_action'' > end > > This works fine but it captures all exceptions even those not related to > validation errors. I want to only capture exceptions when there is some > validation error. If there is some other exception thrown (bug in Rails, > bug in my data objects, etc) then I want it thrown in that page with the > standard Rails debugging info outputted (stack trace, etc.). But > currently if I get some sort of error it redirects to my "failed" page > because I am catching all exceptions. > > So what is the proper exception type I should be catching? > > Eric > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > > >-- Tobi http://www.hieraki.org - Open source book authoring http://blog.leetsoft.com - Technical weblog
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Eric Anderson wrote:> What exception should I be looking for when I rescue a save.Rails does not consider validation errors as exceptional conditions since they are expected and handled by the normal flow of control. Instead, #save returns a boolean indicating whether validation failed, so use a conditional to check whether to redirect or re-render. Example: def edit @obj = Obj.find(@params[''id'']) end def update @obj = Obj.find(@params[''obj''][''id'']) if @obj.update_attributes(@params[''obj'']) redirect_to :action => ''saved'' else render_action ''edit'' end end "Postback" style: def edit case @request.method when :get @obj = Obj.find(@params[''id'']) when :post @obj = Obj.find(@params[''obj''][''id'']) if @obj.update_attributes(@params[''obj'']) redirect_to :action => ''saved'' end # Save failed; proceed to re-render form with errors. end end #update_attributes is equivalent to #attributes= followed by #save jeremy -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.6 (Darwin) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFB8+/4AQHALep9HFYRAtRFAKCgtw1KQGnumoO3iPfTxLUruYVFgwCePZO2 rorJSEGG1jlGB8mN4FA0xbg=wzUX -----END PGP SIGNATURE-----
Here''s an idea inspired by Jeremy''s post: Since the "postback method" is such a common one, why not turn it into a feature of Rails? In other words, make a controller class method that acts as a mini-dispatcher for mentioned methods. If the request is a "get", then send it on to some method ending in _get, or if the request is a "post", send it on to the same prefix but ending in "_post". Here''s one way to do it: class ApplicationController < ActionController::Base def self.postback(symbol) eval "def #{symbol.to_s}; eval \"#{symbol.to_s}_\#{@request.method.to_s}\"; end" end end class NewTestController < ApplicationController postback :new def new_get @test = "get" end def new_post @test = "post" end end The "new.rhtml" view will be rendered in each case. Duane Johnson (canadaduane) On Sun, 23 Jan 2005 10:42:01 -0800, Jeremy Kemper <jeremy-w7CzD/W5Ocjk1uMJSBkQmQ@public.gmane.org> wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Eric Anderson wrote: > > What exception should I be looking for when I rescue a save. > > Rails does not consider validation errors as exceptional conditions > since they are expected and handled by the normal flow of control. > Instead, #save returns a boolean indicating whether validation failed, > so use a conditional to check whether to redirect or re-render. > > Example: > > def edit > @obj = Obj.find(@params[''id'']) > end > > def update > @obj = Obj.find(@params[''obj''][''id'']) > if @obj.update_attributes(@params[''obj'']) > redirect_to :action => ''saved'' > else > render_action ''edit'' > end > end > > "Postback" style: > > def edit > case @request.method > when :get > @obj = Obj.find(@params[''id'']) > when :post > @obj = Obj.find(@params[''obj''][''id'']) > if @obj.update_attributes(@params[''obj'']) > redirect_to :action => ''saved'' > end > # Save failed; proceed to re-render form with errors. > end > end > > #update_attributes is equivalent to #attributes= followed by #save > > jeremy > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.2.6 (Darwin) > Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org > > iD8DBQFB8+/4AQHALep9HFYRAtRFAKCgtw1KQGnumoO3iPfTxLUruYVFgwCePZO2 > rorJSEGG1jlGB8mN4FA0xbg> =wzUX > -----END PGP SIGNATURE----- > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Hello, I''m new here and just building a basic little app to see if rails in for me. anyhow, I see you''re using @obj.update_attributes so I started using it (before I just copied each attribute manually) but I have a question, where should I put logic to make certain attributes immutable such as user.login and user.id? below is what I''m using now but I''d like to move it to the active record somehow, I''m not too sure where to put it.. def update @loadedUser = User.find(loggedInUser.id) case @request.method when :post @params["user"].delete("login") @params["user"].delete("id") if @loadedUser.update_attributes(@params["user"]) flash["notice"] = "User update successful" redirect_to :controller => "user", :action => "profile" else flash["notice"] = "User update failed" add_model_errors_to_action_errors(@loadedUser.errors) #action_errors = @loadedUser.errors end when :get @user = @loadedUser end end Jeremy Kemper wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Eric Anderson wrote: > >>What exception should I be looking for when I rescue a save. > > > Rails does not consider validation errors as exceptional conditions > since they are expected and handled by the normal flow of control. > Instead, #save returns a boolean indicating whether validation failed, > so use a conditional to check whether to redirect or re-render. > > Example: > > def edit > @obj = Obj.find(@params[''id'']) > end > > def update > @obj = Obj.find(@params[''obj''][''id'']) > if @obj.update_attributes(@params[''obj'']) > redirect_to :action => ''saved'' > else > render_action ''edit'' > end > end > > > "Postback" style: > > def edit > case @request.method > when :get > @obj = Obj.find(@params[''id'']) > when :post > @obj = Obj.find(@params[''obj''][''id'']) > if @obj.update_attributes(@params[''obj'']) > redirect_to :action => ''saved'' > end > # Save failed; proceed to re-render form with errors. > end > end > > > #update_attributes is equivalent to #attributes= followed by #save > > jeremy > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.2.6 (Darwin) > Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org > > iD8DBQFB8+/4AQHALep9HFYRAtRFAKCgtw1KQGnumoO3iPfTxLUruYVFgwCePZO2 > rorJSEGG1jlGB8mN4FA0xbg> =wzUX > -----END PGP SIGNATURE----- > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Francisco Hernandez wrote:> but I have a question, where should I put logic to make certain > attributes immutable such as user.login and user.id?In your User model, you may mark certain attributes as protected from mass assignment (#attributes= and #update_attributes.) class User < ActiveRecord::Base attr_protected :login end The primary key attribute (id) is always protected. Add this test case to your User unit tests to verify: def test_login_protected user = User.new user.id = 1 user.login = ''foo'' user.attributes = { :id => 2, :login => ''bar'' } assert_equal 1, user.id assert_equal ''foo'', user.login end jeremy -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.6 (Darwin) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFB9FQ6AQHALep9HFYRAtp6AKCIS+SUUkhGfy2SO4czw4gatgf1zgCfTE1w FGG2YgaUPAtgJSRVb6Ik/jg=hfdA -----END PGP SIGNATURE-----
Use "attr_protected" in your model. From http://api.rubyonrails.com: attr_protected(*attributes) Attributes named in this macro are protected from mass-assignment, such as new(attributes) and attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer methods to do assignment. This is meant to protect sensitive attributes to be overwritten by URL/form hackers. Example: class Customer < ActiveRecord::Base attr_protected :credit_rating end customer = Customer.new("name" => David, "credit_rating" => "Excellent") customer.credit_rating # => nil customer.attributes = { "description" => "Jolly fellow", "credit_rating" => "Superb" } customer.credit_rating # => nil customer.credit_rating = "Average" customer.credit_rating # => "Average" On Sun, 23 Jan 2005 10:42:01 -0800, Jeremy Kemper <jeremy-w7CzD/W5Ocjk1uMJSBkQmQ@public.gmane.org> wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Eric Anderson wrote: > > What exception should I be looking for when I rescue a save. > > Rails does not consider validation errors as exceptional conditions > since they are expected and handled by the normal flow of control. > Instead, #save returns a boolean indicating whether validation failed, > so use a conditional to check whether to redirect or re-render. > > Example: > > def edit > @obj = Obj.find(@params[''id'']) > end > > def update > @obj = Obj.find(@params[''obj''][''id'']) > if @obj.update_attributes(@params[''obj'']) > redirect_to :action => ''saved'' > else > render_action ''edit'' > end > end > > "Postback" style: > > def edit > case @request.method > when :get > @obj = Obj.find(@params[''id'']) > when :post > @obj = Obj.find(@params[''obj''][''id'']) > if @obj.update_attributes(@params[''obj'']) > redirect_to :action => ''saved'' > end > # Save failed; proceed to re-render form with errors. > end > end > > #update_attributes is equivalent to #attributes= followed by #save > > jeremy > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.2.6 (Darwin) > Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org > > iD8DBQFB8+/4AQHALep9HFYRAtRFAKCgtw1KQGnumoO3iPfTxLUruYVFgwCePZO2 > rorJSEGG1jlGB8mN4FA0xbg> =wzUX > -----END PGP SIGNATURE----- > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
exactly what I was looking for, thanks jeremy and duane Jeremy Kemper wrote:> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Francisco Hernandez wrote: > >>but I have a question, where should I put logic to make certain >>attributes immutable such as user.login and user.id? > > > In your User model, you may mark certain attributes as protected from > mass assignment (#attributes= and #update_attributes.) > > class User < ActiveRecord::Base > attr_protected :login > end > > The primary key attribute (id) is always protected. Add this test case > to your User unit tests to verify: > > def test_login_protected > user = User.new > user.id = 1 > user.login = ''foo'' > user.attributes = { :id => 2, :login => ''bar'' } > assert_equal 1, user.id > assert_equal ''foo'', user.login > end > > jeremy > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.2.6 (Darwin) > Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org > > iD8DBQFB9FQ6AQHALep9HFYRAtp6AKCIS+SUUkhGfy2SO4czw4gatgf1zgCfTE1w > FGG2YgaUPAtgJSRVb6Ik/jg> =hfdA > -----END PGP SIGNATURE----- > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Duane Johnson wrote:> Here''s an idea inspired by Jeremy''s post: Since the "postback method" > is such a common one, why not turn it into a feature of Rails? In > other words, make a controller class method that acts as a > mini-dispatcher for mentioned methods. If the request is a "get", > then send it on to some method ending in _get, or if the request is a > "post", send it on to the same prefix but ending in "_post". Here''s > one way to do it:This is a neat idea and a great use of Ruby metaprogramming, but it eliminates this concise (and DRY) postback: def new @obj = Obj.new(@params[''obj'']) # Applies to both get and post. if @request.post? and @obj.save # Save if post. redirect_to :action => ''created'' # Redirect if save succeeded. end # Render if get or save failed. end jeremy -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.6 (Darwin) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFB9JJKAQHALep9HFYRAjZgAJ9e3S/8ks7fjFHtiZe6bAztoOwcTQCfe1z0 9Sy5fYUBdLfFrJggJxzM6Hg=EYGi -----END PGP SIGNATURE-----
> This is a neat idea and a great use of Ruby metaprogramming, but it > eliminates this concise (and DRY) postbackAction Controller used to work somewhat like this in the early days where it differentiated between render and redirects using: def show_view # this would result in a redirect end def do_update # update and redirect end ...but I ultimately found it unsatisfying and I constantly change the prefix because I evolve the methods. I think the current model of just asking @request.post? is as concise as it gets. -- David Heinemeier Hansson, http://www.basecamphq.com/ -- Web-based Project Management http://www.rubyonrails.org/ -- Web-application framework for Ruby http://macromates.com/ -- TextMate: Code and markup editor (OS X) http://www.loudthinking.com/ -- Broadcasting Brain