rails update_attributes method return nil - ruby-on-rails

This is the code:
def update
if #user.update_attributes(params[:user])
redirect_to my_account_path
else
redirect_to account_path
end
end
#user.update_attributes should return true or false when validation failes but it returns nil.
Using Rails 3.1.2 & Ruby 1.9.2.

attr_accessible setup on the model?
http://apidock.com/rails/ActiveRecord/Persistence/update_attributes

Sometimes when I run into issues like this I'll update change update_attributes to update_attributes! -- that can forces an immediate exception to be thrown and can point you at exactly why the value being returned is an error saving.
It should be returning false if the data isn't saved. According to the docs:
If saving fails because the resource is invalid then false will be returned.
And here's this snippet from the rails source (note that update_attibutes calls save under the covers):
def save(*)
begin
create_or_update
rescue ActiveRecord::RecordInvalid
false
end
end
So it specifically returns false, not nil if there's a problem saving the record.

Related

Ruby on Rails Exception usage

Upon finding a failed validation, invalid? will return false and exit.
If all validations pass, invalid? will return true and the code will continue.
Does the rescue code only run if all validations pass?
If so, what raised errors will it catch?
Lastly why is there no Begin?
def save
return false if invalid? # invalid? triggers validations
true
rescue ActiveRecord::StatementInvalid => e
# Handle exception that caused the transaction to fail
# e.message and e.cause.message can be helpful
errors.add(:base, e.message)
false
end
Does the rescue code only run if all validations pass?
Blockquote
No, it will run if the call of invalid? throws an exception of type StatementInvalid
what raised errors will it catch?
Blockquote
the call of invalid? here is what raises the error
why is there no Begin?
in ruby, you can remove begin if you rescue from any exception that is raised from methods body so
def method
begin
#some code
rescue
#handle
end
end
equal to
def method
some code
rescue
# handle
end
but the second syntax shorter and cleaner
Note: it doesn't same right to me to rescue from ActiveRecord::StatementInvalid
inside an override to save

update_attribute not doing anything after first_or_create if record does not exist previously

I do a first_or_create statement, followed by a update_attributes:
hangout = Hangout.where(tour: tour, guide: current_user).first_or_create
hangout.update_attributes(priority: current_user.priority)
If the record already existed, it updates the priority. If it doesn't exist previously, there is no update. Why?
Thanks!
update_attributes (aka update) returns a boolean indicating if there was an error, if you do not check it - use bang-version update! so that exception will not be ignored.
Most probably record does not get created due to validation. Also when you're updating new record just after create - better use first_or_create(priority: current_user.priority) or first_or_initialize(with subsequent update) to spare extra DB write.
def update_attributes!(attributes)
self.attributes = attributes
save!
end
update attribute with bang call the save with bang.
def save!(*args, &block)
create_or_update(*args, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
end
Inside the save! RecordNotSave error will be raise if it cannot save the record.
so you can customize the error handing from your code.
begin
hangout.update_attributes!(priority: current_user.priority)
rescue RecordNotSaved => e
#do the exception handling here
end

show error messages from two models when updating Rails

I am updating the attributes of two models from one form.
User.transaction do
begin
#user.update_attributes!(params[:user])
#board.update_attributes!(params[:board])
rescue ActiveRecord::RecordInvalid
end
end
When the #user.update_attributes produces an error the transaction is stopped and the error message is shown in the view.
However I want to try to update both #user and #board and get the error messages for both so that the user can correct all their mistakes one time.
How can I do this?
Thank you very much in advance.
All you need to do is not use the bang (!) version of update_attributes. Try:
User.transaction do
if #user.update_attributes(params[:user]) && #board.update_attributes(params[:board])
...do stuff...
else
render ... (go back to the action the user got here from)
end
end
Then in your view code put an errors block using a conditional like if #user.errors.any?.
The bang version of update_attribtues and most activerecord methods means it will raise an error if it fails, the regular version just returns false and doesn't save, so you can use that whenever it's ok to fail you just need to take action based on success/failure. Only use the bang version when it's not ok to fail, or when you want to show a 500 screen or something for some reason...
You could do the following:
User.transaction do
#user.update_attributes(params[:user])
#board.update_attributes(params[:board])
raise ActiveRecord::Rollback unless #user.valid? && #board.valid?
end
This will ensure that both update attribute methods run so that you can get error messages for both objects. If either object is invalid though no changes will be persisted to the database.
I think there is some mistake in the method name #user.update_attributes!(params[:user]) it should be like this #user.update_attributes(params[:user]) or once you need cross check your params values whether it is correct or not else your code looks correct. You can have a help with this update_attributes

ActiveRecord 'destroy' method returns a boolean value in Ruby on Rails?

I am using Ruby on Rails 3 and I would like to know what type of return will have the following code:
#user.destroy
I need that to handle cases on success and fault in someway like this:
if #user.destroy
puts "True"
else
puts "false"
end
Is it possible? If so, how?
You should try what you're asking before asking. What you've got there will work just fine.
If the destroy works, it will return the object (which will pass as true in an if statement) and if not, it will return false or raise an exception, depending on why it failed.
It's possible. The destroy method returns the object that was destroyed;
you could use destroyed? on this ActiveRecord object to check if the object is effectively destroyed:
if #user.destroyed?
puts "True"
else
puts "false"
end

In rails, how can I find out what caused a .save() to fail, other than validation errors?

I have an ActiveRecord model which is returning true from valid? (and .errors is empty), but is returning false from save(). If the model instance is valid, how can I find out what's causing the save to fail?
If #user.save (for example) returns false, then just run this to get all the errors:
#user.errors.full_messages
Try using the bang version save! (with an exclamation mark at the end) and inspecting the resulting error.
Check all your callbacks.
I had a problem like this where I had and "after_validate" method that was failing after I had made a bunch of changes to the model. The model was valid but the "after_validate" was returning false, so if I used model.valid it said true, but then if I saved it gave me validation errors (passed through from the after_validate callback). It was weird.
Look at the application trace and you should be able to see what line of code is raising the exception.
Yea, I fixed this issue by making sure I return true in all my before_* callbacks then it starts working :)
Make sure you aren't trying to save a deleted record.
I had the same issue. But unlike the selected answer - my issue wasn't callbacks related.
In my case I had tried to save to a deleted record (deleted from DB).
#user = User.new
#user.save! # user saved to DB
#user.persisted? # true
#user.destroy # user deleted from DB
#user.persisted? # false, user still has its id
#user.valid? # return true
#user.errors # empty
#user.save # return false
#user.save! # raise ActiveRecord::RecordNotSaved
The problem I had was that I had forgotten to add the validation to the model.
class ContactGroup < ActiveRecord::Base
validates_presence_of :name
end

Resources