ActiveRecord like callbacks using ActiveModel
We have seen ActiveRecord callbacks which are executed before or after the object is created or updated. But how do we provide the similar interface for none persistent models. Well here ActiveModel callbacks comes to rescue. ActiveModel Callbacks provides an interface for any class to have Active Record like callbacks. Similar to active record, the callback chain is aborted as soon as one of the methods in the chain returns false.
First of all we will need to require active_model
require 'active_model'
then extend any ruby class with
class Transaction
extend ::ActiveModel::Callbacks
end
Then we need to define a list of methods that we want callbacks attached to using define_model_callbacks
define_model_callbacks :withdraw, :deposit
Here :withdraw and :deposit are the methods where we want to attach callbacks
Defining callback methods using define_model_callbacks allows us to define methods which can be executed before, after and around the model methods ie:; withdraw and deposit methods
This will provide all three standard callbacks (before, around and after) for both the :withdraw and :deposit methods. To implement, we wrap the methods we want callbacks on in a block so that the callbacks get a chance to fire:
def withdraw
run_callbacks :withdraw do
# Our withdraw code here
end
end
def deposit
run_callbacks :deposit do
# Our deposit code here
end
end
run_callbacks tells to run callbacks along with the main model method.
Now we can define which method to execute when (before, after or around) the model method is invoked in the following way.
before_withdraw :check_if_authentic_user
after_deposit :send_confirmation
So we define check_if_authentic_user method and this method gets executed before withdraw method gets executed. Similarly send_confirmation method gets executed after deposit method gets executed.
So our class our overall code becomes
require 'active_model'
class Transaction
extend ::ActiveModel::Callbacks
define_model_callbacks :withdraw, :deposit
before_withdraw :check_if_authentic_user
after_deposit :send_confirmation
def withdraw
run_callbacks :withdraw do
puts "Money withdrawn"
end
end
def deposit
run_callbacks :deposit do
puts "deposited"
end
end
def check_if_authentic_user
puts "Checking if user is authentic"
end
def send_confirmation
puts "Confirmation sent"
end
end
transaction = Transaction.new
transaction.withdraw
transaction.deposit
Outputs
Checking if user is authentic Money withdrawn deposited Confirmation sent
But if we return false from the callback method then the callback chain gets terminated.
For example replace check_if_authentic_user with this.
def check_if_authentic_user
puts "Authenticating user..."
false
end
Our output would be
Authenticating user... deposited Confirmation sent
Since callback method check_if_authentic_user returned false the main :withdraw method never gets executed