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
Related
I came across a scenario where in other languages I would detach the model object from the transaction then I can alter it all I want without worry of an automatic-update to the record.
Question
Does rails not support attaching\detaching a model object?
What is the alternative, just duplicate the object?
EDIT
Scenario
We are reading models out of the database and we want to make changes to them that will not be persisted to the database at the end of the transaction. In Hibernate\JPA etc you detach the model (Entity) and no changes will be persisted.
Now you may ask why not use Model.dup? The answer is that we still need the id of the model but as soon as you assign the id, rails believes this instance is now the model and updates the record at the end of the transaction.
Thanks
You can totally change Rails model instance attributes without persisting the changes.
There are a couple of methods to change model attributes, some of which do automatically persist the changes to the DB and others just change the attribute values of the in-memory instance.
You may want to try using #assign_attributes or #<attribute>= from the above list.
Only after explicitly calling #save afterwards, the changes will be saved to the database.
As stated in a previous answer, you can update instance attributes without persisting them (by avoiding self.save for example). But if you want to be sure, consider the following that uses a validation to check for a flag attribute being nil (or blank):
attr_accessor :prevent_save
validates :prevent_save, absence: true
def prevent_save!
self.prevent_save = true
end
def do_something_safely
prevent_save!
self.other_attr = 'abc'
end
def accidentally_save
# if prevent_save! has been previously called,
# validations will fail, and save! will raise an exception
self.save!
end
I find myself in this situation very often. Sometimes I just take for granted that the record will be saved correctly if I'm in a rush, but I feel as that not being a good practice. I see sometimes placing the if save condition. The question arises here: what are the situations where a record cannot be saved?
what are the situations where a record cannot be saved?
If any of your validations fail. (Or of course HW failure, database connection loss etc occurs).
Should I throw an exception if an item cannot be saved?
If you want an invalid record to result in an exception being thrown, you don't need to do it yourself. Rails can already do it:
If you have a User model with a couple of validations (email and name must be present), you could:
user.save!
With save! validations always run. If any of them fail ActiveRecord::RecordInvalid gets raised.
But you probably don't want an exception to be raised in such a case. Because it is rather "common" for a user to not enter a valid password, for example. But
you should handle errors and the way this is commonly done is:
if user.save
#
else
# handle error
end
By default, save always run validations. If any of them fail the action is cancelled and save returns false.
As a general guideline for choosing between conditionals and exceptions I like this statement from DHH:
Why would the delivery of the emails fail? Because your SMTP server is down? That's an exceptional state, handle it with exceptions -- not with conditions.
Well, not a good title but here is the problem.
[Question updated]
I have two models, Word and Definition. When the user looks up a word the definitions are enlisted and there should be a form below the definitions so that the user can contribute by adding up another definition. So far no problem. But if the search returns no result, I will ask the user to create Word along with its first definition.
I do not know how to deal with the form and logic of the problem. It is more than a nested form. Because something like form_for [#word, #word.definitions.build] do |form| would not work since there is no #word object to which the/a new definition can be referred.
Addendum:
I seem to find a way here. It just works but not so clean to me. If you think there is a better solution please share it anyway.
My approach would be to implement a form object (RailsCast). I'd use a transaction so I'm not left with any orphan database records.
In the submit method of your form object:
def submit
if dictionary_item.present?
# just save the entry
else
# start a transaction so both operations will either succeed or fail
ActiveRecord::Base.transaction do
# save the new dictionary_item
# save the entry
end
end
# return true if the objects are valid and persisted, false otherwise
end
Make sure to call save! or create! inside the transaction. The bangs are important, because an error has to be raised for the transaction to trigger a rollback.
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.
So I've been seeing people using .build, .create, and .create! within their controllers more and more lately. What's the difference from just using .new and passing the param'd object and then .save? Are there pros and cons? Does using these other methods offer benefits?
There are a couple differences, but they're not big:
.create is equivalent to .new followed by .save. It's just more succinct.
.create! is equivalent to .new followed by .save! (throws an error if saving fails). It's also just a wee bit shorter
I think .build is mostly an alias for .new. It works one way in Rails 3 and another way in Rails < 3.x
The most important part, however, is that these methods can be called through an association (has_many, etc.) to automatically link the two models.
Although it is correct that create calls new and then save there is a big difference between the two alternatives in their return values.
Save returns either true or false depending on whether the object was saved successfully to the database or not. This can then be used for flow control as per the first example in the question above.
Create will return the model regardless of whether the object was saved or not. This has implications for the code above in that the top branch of the if statement will always be executed even if the object fails validations and is not saved.
If you use create with branching logic you are at risk of silent failures which is not the case if you use new + save.
create! doesn't suffer from the same issue as it raises and exception if the record is invalid.
The create alternative can be useful in controllers where respond_with is used for API (JSON/XML) responses. In this case the existence of errors on the object will cause the errors to be returned in the response with a status of unprocessable_entity, which is exactly what you want from an API.
I would always use the new + save option for html, especially if you are relying on the return value for flow control.
#create is shorter version of new and save.
#create! is throwing exception if validation was not positive.
I'd second the above answers. Plus for create, one cannot pass false as an argument which you can do with save. Passing false as an argument will skip all rails validations