I'm not sure if this is a rails method or a ruby method but I am looking for details about what happens when you call #object.save.
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save
save is a Rails method defined within the ActiveRecord::Persistence module. It saves the model. If the model is new, a record gets created in the database, otherwise the existing record gets updated.
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.
There’s a series of callbacks associated with the save method. If any of the before_* callbacks return false the action is cancelled and save returns false.
The save! (bang) method always runs validations but raises an ActiveRecord::RecordInvalid exception upon validation failure.
Related
I'm working with a Ruby on Rails application where it was authored to generate some files in the after_save callback. The paperclip gem is used in the class. When these files are created, save is called on the Ruby object which triggers a loop of this second save calling after_save which calls save which calls after_save and on and on.
save! -> after_save -> save! -> after_save!
Eventually somehow the app breaks out of this loop on its own. I'm not sure how.
My question is, if I have an attribute on a class that is changed?=true, when does changed? get flipped to false? We use a changed? check as a sort of gate to prevent this file creation from happening and it seems like changed is always true every time it enters the after_save code. I would've thought that in after_save, changed? would be false by now since the data has been saved.
You should use after_commit with a condition of the key (attribute) present in the previous_changes.
http://apidock.com/rails/ActiveModel/Dirty/previous_changes
I'm using mongoid, and I want to migrate my documents one at a time. To do this, I've tried doing the migration in an after_initialize callback, but I can't seem to save() from there without triggering the same validation and infinite recursion. Is there a better callback to use, or a different thing I should be looking at?
Have you tried passing :validate => false into the save? That allows you to bypass validations.
As per the original question,
instance.update_attributes(new_attr_hash)
will immediately save after updating the instance, but you can't bypass validations with update_attributes.
I'd use before_save, and then go through the whole collection and save them again outside the callback, instead of just initializing them like I assume you were doing before.
Right now, from what I know, after_validation will be called even if the model fails the validations. Is there a way to only call it if the model is valid? I tried adding return false unless self.valid? in the after_validation method but that triggers validation again and it creates an infinite loop.
The failing validations add to the errors for the record, so you could just check:
return false unless self.errors.empty?
Have you thought about using the before_save callback instead?
I believe that will only be called if the object is valid.
I know this is an old question but I ran into the same error when using a custom validation on a model I had created. Looking at the docs there's a part covering custom methods and it states that such validations are called each time the .valid? method. That's probably why the infinite loop got triggered when the :after_validation callback was triggered.
What does this do in Rails?
create! do |user|
#initialise user
end
I figured it creates a user objects and saves it to the database. How is it different from just saying user.new(...) and user.save()?
In a nutshell:
create! raises an exception while create returns the object (unsaved object if it does not pass validations).
save! raises an error while save returns true/false.
save does not take attributes, create does.
new does not save. new is similar to build in ActiveRecord context.
create saves to the database and returns true or false depending on model validations.
create! saves to the database but raises an exception if there are errors in model validations (or any other error).
When failed to create record, create! throws an exception, new and then save (or just create without exclamation mark) exit silently.
create takes attributes , so using a block here is somewhat unusual.
The code you mention is doing the initialization in a block that is passed to create!
It is in principal the same as new followed by the initialization and then a save!
There are many variations save, save!, create, ceate!, update, update!, etc.,
there are also variations in terms of validations, and call-backs
For details please check the API: (it is discussed in the first link)
http://api.rubyonrails.org/classes/ActiveRecord/Base.html
http://apidock.com/rails/ActiveRecord/Base
http://m.onkey.org/active-record-query-interface
I would like load the particular record if it fails the validates_uniqueness constraint.
I have id (primary key) and title in my model. If the user enters a title which is already present if want to search for the record with the title and load that record instead of throwing the error.
Is there a way to do it?
You can use the before_validation callback to check validity yourself, and when it fails, trigger the behavior you're looking for. So, one way to do it would be to write code in before_validation, and in there you could do a simple .valid? call, or manually run the validation for uniqueness by itself. When validation fails, you can stop the callback chain, and trigger custom behavior.
before_validation is one of the many ActiveRecord callbacks available to you.
Another, more common way to do it would be, in your controller, instead of just saving you can basically wrap the .save call in an if statement, because .save returns false if validation fails. You can use this as a way to redirect to an alternate action, in the situation you describe.
#new_record = ThingImSaving.new(params[:thing_im_saving]
if #new_record.save
...validation has passed, continue the normal path
else
...validation has failed, do something else.
end