How to display validation error in Rails during an update operation? - ruby-on-rails

I am having a form and I am trying to save something. Whenever I hit the save button, I am running an update query in the controller. Everything works fine.
I have put a validation in place for one of the text fields which takes text lengths of minimum 5. The error appears while I create the entry. However, when I try to just update, I am not getting any error in the page (validation works though - text is not saved to DB).
How to make sure validation error appears on the page. Following is the sample code.
def save_template
#template = get_template(params[:template])
#template.update_attributes(:label => params[:label])
#some actions later
end
Please help.

The update_attributes method return true if update works and false instead.
So you just render edit template if update failed
def save_template
#template = get_template(params[:template])
unless #template.update_attributes(:label => params[:label])
render :edit
return
end
end

Related

unable to detect attribute changes

Accoding to this stackoverflow post, I can use the following to detect attribute changes:
self.changes
And it does work when I use it in the model, such in an after_update callback:
def check_activity
changes = self.changes
puts changes
end
Unfortunately, it is not working in my controller update action. I tried to use it before the task was saved and after the task was saved:
def update
changes = #task.changes
if #task.update_attributes(task_params)
changes2 = #task.changes
flash[:notice] = "Successfully updated task."
redirect_to polymorphic_path([#taskable, #task])
else
render :edit
end
end
Unfortunately in both cases, it is empty:
Empty ActiveSupport::HashWithIndifferentAccess
What might I be doing wrong?
There aren't any changes to show after you've made the change (IE update_attributes runs)
You could try using assign_attributes instead of update_attributes, checking that everything is valid (object.valid?) getting your changes and then saving
Just check out ActiveModel::Dirty
Changes method does not returns changes after save.you should use it in before save, if you want to check the value after save use these ones previous_changes etc. for detail checkout http://api.rubyonrails.org/classes/ActiveModel/Dirty.html.

Update attributes for User only if attributes have changed

The original, happily working version of my project looked like this:
1) User fills out form (new action) and hits submit (create action)
2) User is redirected to their edit page (edit action uses an edit_id created by model, not Rails auto-gen id), which shows the info user had already submitted
3) User can choose to change info (update action) and re-submit
In this version, even if the user changes nothing in the edit page and submits, the page will still flash a success alert.
From a database perspective, I don’t really care, because since the form is prefilled with the user’s info, the update_attributes method is just overriding old info with the same info.
From a user perspective though, it's annoying, so I want to ensure that the info is only updated and the success alert flashed only if the user actually changes something.
I thought this would be really easy, changing the old code from this:
def update
#request = Request.find_by_edit_id(params[:edit_id])
if #request.update_attributes(request_params)
flash[:success] = true
redirect_to edit_request_path(#request.edit_id)
else
render 'edit'
end
end
And adding one additional component to the "if" like this:
def update
#request = Request.find_by_edit_id(params[:edit_id])
if #request.update_attributes(request_params) && #request.changed?
flash[:success] = true
redirect_to edit_request_path(#request.edit_id)
else
render 'edit'
end
end
But this doesn’t work. Now what happens is that, on the edit page, if I don’t change any info and hit submit, nothing happens (which is great), but if I DO change info and hit submit, still nothing happens (which is bad). What am I doing wrong?
Note: I initially thought it was an order of operations error, so I made it a nested if, with first if #request.update_attributes, and second if #request.changed, but this didn't work either...
The update_attributes method includes the 'save' call as part of its method and is returning true if the save is successful. I think you're looking for something like this using assign_attributes:
def update
#request = Request.find_by_edit_id(params[:edit_id])
#request.assign_attributes(request_params)
if #request.changed?
if #request.save
flash[:success] = true
redirect_to edit_request_path(#request.edit_id)
else
render 'edit'
end
else
# Action if no change has been made
end
end

update_attributes isn't saving to the database

The correct custom params are being displayed in my debug function after the form is submitted but the default params are displayed when I enter console.
Controller
def update
current_user.update_attributes(params[:user])
flash[:success] = "Your settings have been saved!"
render new_status_update_path
end
Model
attr_accessible :deficit_pct,
:target_bf_pct,
:activity_factor
Notes:
The closest question I could find to this on SO is a question that changes the attributes of an object that exists through an association.
I've tried using the Object.update method although I get an error that says:
private method `update' called for #
Any ideas?
Thanks!
Try the code :-
def update
if current_user.update_attributes(params[:user])
flash[:success] = "Your settings have been saved!"
render new_status_update_path
else
p 111111111111
p current_user.errors.inspect
end
end
after check your log for any errors.exist for that active record
After playing around with in the console I've found out that even if I change the attributes manually the attributes don't 'stick' after I exit the console.
So I'll enter console, change the users attributes, test them, and they'll be changed. If I exist and re-enter, THEN test them, they'll have reverted back to their default values.
This leads me to believe that the 'after_initialize' method within the user model which sets its default values is running after each save. I though that it would only run after the object had been saved for the first time alone but now I know it run each time it is saved.
after_initialize :default_values
def default_values
self.goal = "Cut"
self.measurement = "US"
self.bmr_formula = "katch"
self.fat_factor = 0.655
self.protein_factor = 1.25
self.deficit_pct = 0.10
self.target_bf_pct = 0.10
self.activity_factor = 1.3
end
Once I remove all these values and the after_initialize method, it saves permanently.
You should make sure that you don't have any validation errors. You can check them using:
active_record_model.errors
In your case, it would be
current_user.errors
Also, you should print the return value from update_attributes to see if it's true or false. If you get false, the save was cancelled. This was most likely caused by validation errors or a callback returning false.
Something like:
def update
if current_user.update_attributes(params[:user])
flash[:success] = "Your settings have been saved!"
render new_status_update_path
else
some_error_handling_code
end
end
Would not display success when the save fails. As a general rule, you should check whether a save, or any other back end operation, fails, before reporting success to the end user.

Rails Controller Object.save

I am working through Head First Rails and I came across some code that is confusing me a little. The goal of the code is to check and see if any error was made when a new record is being created. If there is an error, then the goal is the redisplay the page. If there is no error, the goal is to save the record to the database. Here is the controller code that the book gives:
def create
#ad = Ad.new(params[:ad])
if #ad.save
redirect_to "/ads/#{#ad.id}"
else
render :template => "ads/new"
end
end
The only thing about this code that confuses me is the fact the line (if #ad.save). Now, I know this line is testing to see if there are errors. If there are, it returns false, and if there are not, it returns true. However, I noticed that if no errors exist (it returns true), the record is actually saved. I thought "if" statments in ruby just tested a condition, but in this case, the condition is being tested AND executed. The strange this is that if I add another #ad.save, the database DOES NOT save the record twice. Like so:
def create
#ad = Ad.new(params[:ad])
if #ad.save
#ad.save
redirect_to "/ads/#{#ad.id}"
else
render :template => "ads/new"
end
end
This code does the exact same thing as the first bit of code. Why in the first bit of code is the #ad.save being executed, and how come on the second bit of code the #ad.save is not executed twice (only one record is created)?
Your assumption about if statements in ruby is incorrect. They can in fact execute code.
def return_true
puts 'inside method'
true
end
if return_true
puts "it ran some code"
end
# output will be:
# inside method
# it ran some code
In your second example the save is being run at least once. If the result of #as.save is truthy then it's run a second time. If it is going through the first part of the if branch then something else is preventing it from being saved to the database twice but there's not enough info for me to tell why. It could be that you have a unique contraint. Try doing #ad.save!. The bang version will throw an error if there are any validation errors.

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

Resources