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.
Related
So i have my form and in my controller i have my update method as follows
def update
#student = Student.find(params[:id])
if #student.update_attributes!(student_params)
#student.read_notes = true
#here i check if the records changed or not?
ap #student.name_changed?
end
end
def student_params
params.require(:student).permit(:name, :email, :age, :class)
end
This fails as i always get the false response each time even though i have actually made changes to the name record.
How do i actually track my changes in my record if i am updating via this way?
When you save the record (which update_attributes!, update!, and update will all do), Rails' "dirty tracking" resets and you lose the ability to easily tell if anything changed. What you could do instead is use assign_attributes, like so:
def update
#student = Student.find(params[:id])
#student.assign_attributes(student_params)
if #student.name_changed?
# ...
end
#student.save!
end
There's also an ActiveRecord method called previous_changes, which stores changes made after a save. This article goes into detail on how to use that.
You could also simply track if the name parameter differs from the record's name, or store the value prior to the update and compare it afterward, depending on your needs.
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.
Suppose i have a model User and a controller UsersController,
in my create actions, i can write
def create
#user = User.new(user_params)
#user.save
redirect_to root_path
end
or
#user = User.new(uer_params)
if #user.save
redirect_to users_path
else
render :new
end
Replicate above 2 actions for Update and destroy also
My question is related to 2nd create action,
Is is necessary to add if else end. what worse could happen i just have create actions like 1st one.
Note: Please ignore the validations part for now.
Just suppose I do not any validations.
What are the other possible conditions in which create/update/destroy will fail apart from validations and which one is the good practice.
Given that you don't want to perform any validations or any checks on the status of the save, then there's no reason for the conditional. In fact, in that case there's also no reason for the #user instance variable. This is all you would need:
def create
User.create(user_params)
redirect_to root_path
end
The conditional is just to do different things based on the status of the save. The instance variable is only to pass the User object to the view. But if you're always doing a redirect then you can't utilize the instance variable anyway, so no need.
What's "right" here is up to the needs of your application. Do the minimum necessary until you have a problem and then fix it.
This:
if User.create(user_params)
is always true. create returns on active reocrd object regardless whether it was successfully created or not. This is why we usually do:
#user = User.new(uer_params)
if #user.save
redirect_to users_path
else
render :new
end
Also note that we are ot redirecting to a new action. The reason is that we already has an #user variable, which 1) holds all the attributes entered by user 2) has all the validation errors attached to it. All we need to do is to render :new template and let Rails do its magic.
Note: If we ignore the validation, then there is no difference which option you will use. You don't need if/else statement neither as it will throw an exception if save fails for any other reason than validation (unless you have after/before_save hooks).
Difference between create & save ?
From the docs:
create
Tries to create a new record with the same scoped attributes defined
in the relation. Returns the initialized object if validation fails
save
.... By default, save always run validations. If any of them fail the
action is cancelled and save returns false. However, if you supply
validate: false, validations are bypassed altogether.
What about validations?
Well,
Create will try saving and returns the initialized object anyway (successful or failed save after validations)
Save will try saving and returns true for successful save and false otherwise
Note that you can skip validations by passing false to save
#user.save(false)
So, what about Conditions?
If you chose to skip validations, using Create or Save(false) then you don't need conditions, while if you need validations then you probably need to check how things went then give user some feedback, hence the conditions
I am maintaining someone's code base and they have something like this:
if #widget_part.destroy
flash[:message] = "Error deleting widget part"
else
flash[:message] = "Widget part destroyed successfully"
end
What does destroy return? Is it ok to test like this? The reason I'm asking is that I tried to use
flash[:message] = "Error deleting widget part : #{#widget_part.errors.inspect}"
and there are no error messages so I am confused. It gives something like
#<ActiveModel::Errors:0x00000103e118e8 #base=#<WidgetPart widget_id: 7, ...,
id: 67>, #messages={}>
If you're unsure, you can use destroyed? method. Return value of destroy is undocumented, but it returns just freezed destroyed object (you cannot update it). It doesn't return status of destroy action.
Although generally destroying object should always succeed, you can listen for ActiveRecordError. For example Optimistic Locking can raise ActiveRecord::StaleObjectError on record destroy.
As some people mentioned above, that destroy does not return a boolean value, instead it returns a frozen object. And additionally it does update the state of the instance object that you call it on. Here is how I write the controller:
#widget_part.destroy
if #widget_part.destroyed?
flash[:success] = 'The part is destroyed'
else
flash[:error] = 'Failed to destroy'
end
According to the Ruby on Rails API documentation, the destroy method will return the object that you destroyed, but in a frozen state.
When an object is frozen, no changes should be made to the object since it can no longer be persisted.
You can check if an object was destroyed using object.destroyed?.
Note that while #destroyed? works in the OP’s case, it only works when called on the same model instance as #destroy or #delete; it doesn’t check the database to see if the underlying record has been deleted via a different instance.
item1 = Item.take
# => #<Item:0x00000001322ed3c0
item2 = Item.find(item1.id)
# => #<Item:0x00000001116b92b8
item1.destroy
# => #<Item:0x00000001322ed3c0
item1.destroyed?
# => true
item2.destroyed?
# => false
item2.reload
# => raises ActiveRecord::RecordNotFound
If you need to check whether another process has deleted the record out from under you (e.g. by another user, or in a test where the record is deleted via a controller action), you need to call #exists? on the model class.
Item.exists?(item2.id)
# => false
I have a model named Post and I created two methods within the model that make changes to fields. The first method's changes get persisted when a save is called. The second method's changes do not get saved. I have noticed this behavior before in other models and I think I'm missing some basic knowledge on how models work. Any help on this would be greatly appreciated!
class Post < ActiveRecord::Base
def publish(user) # These changes get saved
reviewed_by = user
touch(:reviewed_at)
active = true
end
def unpublish() # These changes get ignored.
reviewed_by = nil
reviewed_at = nil
active = false
end
end
EDIT:
Here is a snippet from the controller"
class PostsController < ApplicationController
def publish
if request.post?
post = Post.find(params[:id].to_i)
post.publish(current_user)
redirect_to(post, :notice => 'Post was successfully published.')
end
end
def unpublish
if request.post?
post = Post.find(params[:id].to_i)
post.unpublish()
redirect_to(post, :notice => 'Post was successfully unpublished.')
end
end
...
UPDATE
Problem was solved by adding self to all the attributes being changed in the model. Thanks Simone Carletti
In publish you call the method touch that saves the changes to the database. In unpublish, you don't save anything to the database.
If you want to update a model, be sure to use a method that saves the changes to the database.
def publish(user)
self.reviewed_by = user
self.active = true
self.reviewed_at = Time.now
save!
end
def unpublish
self.reviewed_by = nil
self.reviewed_at = nil
self.active = false
save!
end
Also, make sure to use self.attribute when you set a value, otherwise the attribute will be consideres as a local variable.
In my experience you don't persist your changes until you save them so you can
explicitly call Model.save in your controller
explicitly call Model.update_attributes(params[:model_attr]) in your controller
if you want to save an attribute in your model I saw something like write_attribute :attr_name, value but TBH I never used it.
Cheers