What the heck is a call back method in rails? I see this term being used everywhere while I learn about controllers and models. Can someone provide examples please?
Ref ActiveRecord::Callbacks for the Callbacks w.r.to Activerecord
Callbacks are hooks into the lifecycle of an Active Record object that allow you
to trigger logic before or after an alteration of the object state. This can be
used to make sure that associated and dependent objects are deleted when destroy
is called (by overwriting before_destroy) or to massage attributes before they‘re
validated (by overwriting before_validation). As an example of the callbacks
initiated, consider the Base#save call for a new record
Take an example you have a Subscription model and you have a column signed_up_on which will contains the date at which subscription is created. For this w/o Callbacks you can do something like following in your controller.
#subscription.save
#subscription.update_attribute('signed_up_on', Date.today)
Which will perfectly fine but if suppose you have 3-4 methods in your application where subscription is get create. So to achieve it you have repeat the code in all the places which is redundant.
To avoid this you can use Callbacks and before_create Callback here. So whenever your object of subscription is get create it will assign today's date to signed_up_on
class Subscription < ActiveRecord::Base
before_create :record_signup
private
def record_signup
self.signed_up_on = Date.today
end
end
Following is the list of all the Callbacks
after_create
after_destroy
after_save
after_update
after_validation
after_validation_on_create
after_validation_on_update
before_create
before_destroy
before_save
before_update
before_validation
before_validation_on_create
before_validation_on_update
Related
I have a user table and a setting table with 1-1 relationship. I want to insert some default setting for the newly created user. I am thinking to use after_create callback of user. However, I am not sure if this will be transactional. What is the best approach for this condition?
You may find after_initialize callback useful for building the setting object for user and assigning default setting. Example:
class User < ActiveRecord::Base
has_one :setting
after_initialize :init_user_setting
private
def init_user_setting
# Assign default setting or build
self.setting = ...
end
end
With this you'll have your complete parent user including child setting. When you call user.save both user and setting are saved and both happen inside a transaction.
You can use after_create callback or observer both. Both will be okay. But You should also set your default values for settings in a initialize method for attribute assignment. Or you can also use user's create method to do same after save call. But it's not a good way. So prefer either call_back or observer.
--UPDATE--
As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model's validations, the registered callbacks, and the database operation to be executed.
The whole callback chain is wrapped in a transaction. If any before callback method returns exactly false or raises an exception, the execution chain gets halted and a ROLLBACK is issued; after callbacks can only accomplish that by raising an exception.
After setting an attribute to false at the end of a before_save callback, I could not for the life of me figure out why the object would never save! Before callbacks must return truthy values or it will rollback.
--Previous--
You need to do something like this. This is my default approach for anything short of dealing with currency.
class User < ActiveRecord::Base
has_one :setting
after_create :setup_user
private
def setup_user
user_settings = self.setting.new
user_settings.attr1 = foo1
user_settings.attr2 = foo2
user_settings.save
end
end
class Setting < ActiveRecord::Base
belongs_to :user
end
Ideally you would put validations on the user and make it so that if a user is valid a setting is also valid. But if you don't do that, you need to use
if !user_settings.save
self.destroy
end
For where to put the default values,if the setting default values depend on the user, stick them in the setup_user method. If the setting default values doesn't care about the user, stick them in a before_save or before_validation method on the setting. With regards to the user, you need to use an after_create method for the case where a user doesn't validate, you want those callbacks to only fire if a user is successfully created. You don't want to user after_validation because the user would not have been created and if the setting contains a foreign id to the user that is not yet created, for an instant your database will be inconsistent.
Transaction based approach
class User < ActiveRecord::Base
has_one :setting
after_commit :setup_user, on: [:create]
after_rollback :undo_user, on: [:create]
private
def setup_user
user_settings = self.setting.new
user_settings.attr1 = foo1
user_settings.attr2 = foo2
user_settings.save!
end
def undo_user
#The users settings didn't save so roll back the user
self.destroy
end
end
class Setting < ActiveRecord::Base
belongs_to :user
end
To put it in the same transaction you need to use after_commit and after_rollback. Using .save! will throw an exception and trigger after_rollback. You will not have a user without the setting.
I know that before_create is called before the object gets commuted to the database and after_create gets called after.
The only time when before_create will get called and after_create while not is if the object fails to meet data base constants (unique key, etc.). Other that that I can place all the logic from after_create in before_create
Am I missing something?
In order to understand these two callbacks, firstly you need to know when these two are invoked. Below is the ActiveRecord callback ordering:
(-) save
(-) valid
(1) before_validation
(-) validate
(2) after_validation
(3) before_save
(4) before_create
(-) create
(5) after_create
(6) after_save
(7) after_commit
you can see that before_create is called after after_validation, to put it in simple context, this callback is called after your ActiveRecord has met validation. This before_create is normally used to set some extra attributes after validation.
now move on to after_create, you can see this is created after the record is stored persistently onto DB. People normally use this to do things like sending notification, logging.
And for the question, when should you use it? The answer is 'you should not use it at all'. ActiveRecord callbacks are anti-pattern and seasoned Rails developer consider it code-smell, you can achieve all of that by using Service object to wrap around. Here is one simple example:
class Car < ActiveRecord::Base
before_create :set_mileage_to_zero
after_create :send_quality_report_to_qa_team
end
can be rewritten in
# app/services/car_creation.rb
class CarCreation
attr_reader :car
def initialize(params = {})
#car = Car.new(params)
#car.mileage = 0
end
def create_car
if car.save
send_report_to_qa_team
end
end
private
def send_report_to_qa_team
end
end
If you have simple app, then callback is okay, but as your app grows, you will be scratching your head not sure what has set this or that attribute and testing will be very hard.
On second thought, I still think you should extensively use callback and experience the pain refactoring it then you'll learn to avoid it ;) goodluck
The before_create callback can be used to set attributes on the object before it is saved to the database. For example, generating a unique identifier for a record. Putting this in an after_create would require another database call.
before_create:
will be called before saving new object in db. When this method will return false it will prevent the creation by rolling back.
So when you need to do something like check something before saving which is not appropriate in validations you can use them in before_create.
For example: before creation of new Worker ask Master for permission.
before_create :notify_master
def notify_master
# notify_master via ipc and
# if response is true then return true and create this successfully
# else return false and rollback
end
Another use is as Trung Lê suggested you want to format some attribute before saving
like capitalizing name etc.
after_create:
Called after saving object in database for first time. Just when you don't want to interrupt creation and just take a note of creation or trigger something after creation this is useful.
for example: After creating new user with role mod we want to notify other mods
after_create :notify_mod, :is_mod?
def notify_mod
# send notification to all other mods
end
EDIT: for below comment
Q: What's the advantage of putting notify_mod in after_create instead of before_create?
A: Sometimes while saving the object in database it can rollback due to database side validations or due to other issues.
Now if you have written notify_mod in before create then it will be processed even if the creation is not done. No doubt it will rollback but it generates overhead. so it's time consuming
If you have placed it in after_create then notify_mod will only execute if the record is created successfully. Thus decreasing the overhead if the rollback takes places.
Another reason is that it's logical that notification must be sent after user is created not before.
Is it possible for a web application developed using the Ruby on Rails framework to intercept all calls to it with a third party security tool? Any call to this web application goes to security tool instead of web application itself and then security tool can redirect it to web application.
Similar on the response side, web application responses are intercepted by security tool before send it to client (browser)
you can use befor_methods to do this if i understand what you want to do correctly
Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic before or after an alteration of the object state. This can be used to make sure that associated and dependent objects are deleted when destroy is called (by overwriting before_destroy) or to massage attributes before they're validated (by overwriting before_validation). As an example of the callbacks initiated, consider the Base#save call for a new record:
(-) save
(-) valid
(1) before_validation
(-) validate
(2) after_validation
(3) before_save
(4) before_create
(-) create
(5) after_create
(6) after_save
(7) after_commit
Also, an after_rollback callback can be configured to be triggered whenever a rollback is issued. Check out ActiveRecord::Transactions for more details about after_commit and after_rollback.
Additionally, an after_touch callback is triggered whenever an object is touched.
Lastly an after_find and after_initialize callback is triggered for each object that is found and instantiated by a finder, with after_initialize being triggered after new objects are instantiated as well.
There are nineteen callbacks in total, which give you immense power to react and prepare for each state in the Active Record life cycle. The sequence for calling Base#save for an existing record is similar, except that each _create callback is replaced by the corresponding _update callback.
Examples:
class CreditCard < ActiveRecord::Base
# Strip everything but digits, so the user can specify "555 234 34" or
# "5552-3434" and both will mean "55523434"
before_validation(on: :create) do
self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
end
end
class Subscription < ActiveRecord::Base
before_create :record_signup
private
def record_signup
self.signed_up_on = Date.today
end
end
class Firm < ActiveRecord::Base
# Destroys the associated clients and people when the firm is destroyed
before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
end
Could you explain in detail what the :before_save and :before_create Ruby on Rails callbacks are, and what they have to do with Rails validations? Does validation occur after :before_save or :before_create?
In a create operation under Rails, there are six callbacks before the database operation, and two after. In order, these are:
before_validation
before_validation_on_create
after_validation
after_validation_on_create
before_save
before_create
DATABASE INSERT
after_create
after_save
Update operations have exactly the same set, except read update instead of create everywhere (and UPDATE instead of INSERT).
From this, you can see that validation is carried out before the before_save and before_create callbacks.
The before_save occurs slightly before the before_create. To the best of my knowledge, nothing happens between them; but before_save will also fire on Update operations, while before_create will only fire on Creates.
before_save is called every time an object is saved. So for new and existing objects. (create and update action)
before_create only before creation. So only for new objects (create action)
before_create vs before_save :on => :create
Sometimes you have to be careful of the order of the callbacks
See here for more details:
http://pivotallabs.com/activerecord-callbacks-autosave-before-this-and-that-etc/
Does val_presence_of get called before the 'before_save' event?
how do I set a default value on a model's property?
Use before_validation callbacks:
class User
before_validation(:on => :create) do
self.time_zone ||= "Blah"
end
end
Yes, all of your validations are run before the before_save callback is fired. For the complete list in order, see http://guides.rubyonrails.org/active_record_validations_callbacks.html#available-callbacks.
I would recommend using after_initialize. That's really what it's intended for. It means that it gets called for objects when they're loaded from the database, as well as when they're first created. In other words, their attributes are consistently what you expect them to be.
class User
def after_initialization
self.foobar ||= 'default value'
end
end
From the docs:
The after_initialize callback will be
called whenever an Active Record
object is instantiated, either by
directly using new or when a record is
loaded from the database. It can be
useful to avoid the need to directly
override your Active Record initialize
method.
The after_find callback will be called
whenever Active Record loads a record
from the database. after_find is
called before after_initialize if both
are defined.
The after_initialize and after_find
callbacks are a bit different from the
others. They have no before_*
counterparts, and the only way to
register them is by defining them as
regular methods. If you try to
register after_initialize or
after_find using macro-style class
methods, they will just be ignored.
This behaviour is due to performance
reasons, since after_initialize and
after_find will both be called for
each record found in the database,
significantly slowing down the
queries.