Reputation: 723
I add the following override for a controller that I inherit from a gem (Spree):
module Spree
module Admin
UsersController.class_eval do
def index
if params[:role].present?
included_users = Spree::User.joins(:role_users).
where( spree_role_users: { role_id: params[:role] } ).map(&:id)
flash[:notice] = "Filtered in #{included_users.count} users"
@users = @users.where(id: included_users)
end
end
end
end
end
Basically, it filters by an additional parameter on the Admin::UsersController
controller. The source for that controller in the gem doesn't actually define the index
method, so mine just gets called instead.
Now, this works perfectly well in development. However, in production, this method never gets called.
Is there something about class_eval
that I'm not getting here? Shouldn't things like this work basically the same in production as they do in development?
Thanks for any help.
Upvotes: 0
Views: 1233
Reputation: 102240
Decorators are objects that wrap another object. For example they are often used to wrap models with presentational logic.
class UserDecorator < SimpleDelegator
def full_name
"#{first_name} #{last_name}"
end
end
> @user = UserDecorator.new(User.new(first_name: 'John', last_name: 'Doe'))
> @user.full_name
=> "John Doe"
This is not a decorator method - you are just reopening the class and adding a method. This is known as monkey-patching.
Using class_eval
in this case exactly the same in this as using the class keyword:
module Spree
module Admin
class UsersController
def index
if params[:role].present?
included_users = Spree::User.joins(:role_users).
where( spree_role_users: { role_id: params[:role] } ).map(&:id)
flash[:notice] = "Filtered in #{included_users.count} users"
@users = @users.where(id: included_users)
end
end
end
end
end
With monkey-patches the key is ensuring that your class redefinition is read. I'm guessing the difference between dev and production is due to class catching which prevents the class from being read from /app
if it has already been defined by the Spree gem. config/application.rb
uses bundler to require all the gems when the application starts up.
You can assure that a monkey-patch is loaded by placing it in config/initializers
as all files in that directory are loaded on startup.
But a better alternative to monkeypatching may be to instead subclass the vendor controller and route to it:
class MyUsersController < ::Spree::Admin::UsersController
def index
if params[:role].present?
included_users = Spree::User.joins(:role_users).
where( spree_role_users: { role_id: params[:role] } ).map(&:id)
flash[:notice] = "Filtered in #{included_users.count} users"
@users = @users.where(id: included_users)
end
end
end
Upvotes: 1