How to properly monkey-patch a Ruby Class in Ruby on Rails?
Sometimes, when we use an existing Ruby Class from a third-part gem, we need to monkey-patch it to fit our project’s needs.
Don’t use class_eval
We often see the usage of class_eval
to override a Ruby Class.
In this example, we want to permit new params: :show_in_main_menu
, :show_in_footer
and :css_class
.
# app/decorators/controllers/refinery/admin/pages_controller_decorator.rb
Refinery::Admin::PagesController.class_eval do
def permitted_page_params
[
:show_in_main_menu, :show_in_footer, :css_class,
:browser_title, :draft, :link_url, :menu_title, :meta_description,
:parent_id, :skip_to_first_child, :show_in_menu, :title, :view_template,
:layout_template, :custom_slug, parts_attributes: permitted_parts_attributes_params
]
end
end
By using class_eval
, you have to copy/paste the all content of the permitted_page_params
method.
Now this overriden method is no more synced from the third-part gem and could probably break if the original method is modified in the gem.
Use Module#prepend
Instead of using class_eval
, you should use Module#prepend
:
# app/decorators/controllers/refinery/admin/pages_controller_decorator.rb
module RefineryAdminPagesControllerDecorator
def permitted_page_params
super << %i[show_in_main_menu show_in_footer css_class]
end
end
Refinery::Admin::PagesController.send :prepend, RefineryAdminPagesControllerDecorator
By using Module#prepend
, we can call the super
method to retrieve the original content of the method: an Array in
this case. It allows us to just push the new params in this Array.
It’s a simpler and more robust solution!
NOTE: In this guide we use Ruby on Rails, so we will probably need to tell our application how to load these decorators :
# config/application.rb
config.to_prepare do
# Load application's model / class decorators
Dir.glob(File.join(File.dirname(__FILE__), '../app/**/*_decorator*.rb')) do |c|
Rails.configuration.cache_classes ? require(c) : load(c)
end
end
who love Ruby, Ruby on Rails and Reactive technologies.
I create web applications that help companies to propel their business model.