Rails 装饰器方法未在生产中调用,在开发中有效
Rails decorator method not being called in production, works in development
我为从 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
基本上,它通过 Admin::UsersController
控制器上的附加参数进行过滤。 gem 中那个控制器的源实际上并没有定义 index
方法,所以我的只是被调用。
现在,这在开发中非常有效。但是,在生产中,此方法永远不会被调用。
有什么关于 class_eval
的事情我没有说到这里吗?这样的事情不应该在生产中和在开发中基本一样吗?
感谢您的帮助。
装饰器是包装另一个对象的对象。例如,它们通常用于包装具有表示逻辑的模型。
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"
这不是装饰器方法 - 您只是重新打开 class 并添加一个方法。这被称为 monkey-patching.
在这种情况下使用 class_eval
与使用 class 关键字完全相同:
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
使用 monkey-patches 的关键是确保您的 class 重新定义被读取。我猜 dev 和 production 之间的区别是由于 class catching 阻止 class 从 /app
读取,如果它已经被 Spree gem 定义. config/application.rb
使用捆绑器在应用程序启动时要求所有 gem。
您可以通过将猴子补丁放在 config/initializers
中来确保加载它,因为该目录中的所有文件都在启动时加载。
但是 monkeypatching 的一个更好的替代方法可能是代替 class 供应商控制器和 route 它:
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
另见:
我为从 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
基本上,它通过 Admin::UsersController
控制器上的附加参数进行过滤。 gem 中那个控制器的源实际上并没有定义 index
方法,所以我的只是被调用。
现在,这在开发中非常有效。但是,在生产中,此方法永远不会被调用。
有什么关于 class_eval
的事情我没有说到这里吗?这样的事情不应该在生产中和在开发中基本一样吗?
感谢您的帮助。
装饰器是包装另一个对象的对象。例如,它们通常用于包装具有表示逻辑的模型。
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"
这不是装饰器方法 - 您只是重新打开 class 并添加一个方法。这被称为 monkey-patching.
在这种情况下使用 class_eval
与使用 class 关键字完全相同:
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
使用 monkey-patches 的关键是确保您的 class 重新定义被读取。我猜 dev 和 production 之间的区别是由于 class catching 阻止 class 从 /app
读取,如果它已经被 Spree gem 定义. config/application.rb
使用捆绑器在应用程序启动时要求所有 gem。
您可以通过将猴子补丁放在 config/initializers
中来确保加载它,因为该目录中的所有文件都在启动时加载。
但是 monkeypatching 的一个更好的替代方法可能是代替 class 供应商控制器和 route 它:
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