Blog #6
Let's imagine a situation - You need create multiple methods with similar purposes (same name and same logic) but doing so will have repetitions, so it will not be optimal, making the code file become more versbose.
def create_order_cod
order = Order.not_draft.where(payment_method: :cod).last
OrderMailer.create_order_email(order.id)
end
def create_order_transfer
order = Order.not_draft.where(payment_method: :transfer).last
OrderMailer.create_order_email(order.id)
end
def create_order_paypal
order = Order.not_draft.where(payment_method: :paypal).last
OrderMailer.create_order_email(order.id)
end
I had this problem when trying to create email preview methods like above.
Before we start to deal with this, let's state our wish first, which is to create a loop that generates methods by the names we give them.
Ruby on Rails
supports a method that can help us do just that, it's called define_method
.
Just to be clear, we can do this:
define_method(:my_method) do |foo, bar| # or even |*args|
# do something
end
This means same as:
def my_method(foo, bar)
# do something
end
If you want to define method parameters that have default values, you need to get a bit more creative and do something like this:
define_method(:my_method) do |foo, bar|
bar ||= {}
# do something
end
So with my case, I edited as follows:
Order.payment_methods.each_key do |payment_method|
define_method("create_order_#{payment_method}") do
order = Order.not_draft.where(payment_method: payment_method).last
OrderMailer.create_order_email(order.id)
end
end
Although define_method
helps us to solve the long-winded problem, it also comes with the disadvantage that when maintaining the code, it is difficult to find the methods that are generated by this method.
Use it carefully or it will become your own obsession :D