如何在 class 中正确添加模块?
How to correctly prepend module in a class?
我有一个AccountControllerclass,这个控制器class在应用程序内核中。我不想更改内核,因此我打算使用 Monkey Patch。
控制器具有名为 successful_authentication 的方法,我已将其重写。在新方法(在我的模块中)中,此代码调用名为 load_favourite_or_index.
的新方法
我了解到 alias_method_chain 现在已弃用,不应再使用。我试图在 AccountController 之前 prepend 我的模块。但是没有任何反应,我想我的前置代码不正确,请你帮帮我好吗?这是我的代码。
# frozen_string_literal: true
module RedmineKapDesign
module Patches
module AccountControllerPatch
def self.prepended(base) # :nodoc:
class << base
prepend InstanceMethods
end
end
module InstanceMethods
def successful_authentication(user)
logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
# Valid user
self.logged_user = user
logger.info "Setting.autologin? = #{Setting.autologin?}, params[:autologin] = #{params[:autologin]}"
# generate a key and set cookie if autologin
if params[:autologin] && Setting.autologin?
set_autologin_cookie(user)
end
call_hook(:controller_account_success_authentication_after, {:user => user})
load_favourite_page_or_index
#redirect_back_or_default my_page_path
end
def load_favourite_page_or_index
user = User.current
favourite_page_field = CustomField.where(name: ["Favourite page", "favourite page", "favorite page", "Favourite page", "Любимая страница", "любимая страница", "Избранная страница", "избранная страница"]).first
page_url = user.custom_values.where(custom_field_id: favourite_page_field.id).first.value
if page_url.empty?
redirect_back_or_default my_page_path
else
redirect_to(page_url)
end
end
def self.hello
puts "Hello"
end
end
end
end
end
#unless AccountController.included_modules.include?(RedmineKapDesign::Patches::AccountControllerPatch)
# AccountController.send(:prepend, RedmineKapDesign::Patches::AccountControllerPatch)
#end
AccountController.singleton_class.prepend(RedmineKapDesign::Patches::AccountControllerPatch)
您不需要将实例方法分离到一个单独的模块中。您可以将它们放在 AccountControllerPatch 中并添加任何 class 您正在使用它进行猴子修补的内容。
module RedmineKapDesign
module Patches
module AccountControllerPatch
def successful_authentication(user)
logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
# Valid user
self.logged_user = user
logger.info "Setting.autologin? = #{Setting.autologin?}, params[:autologin] = #{params[:autologin]}"
# generate a key and set cookie if autologin
if params[:autologin] && Setting.autologin?
set_autologin_cookie(user)
end
call_hook(:controller_account_success_authentication_after, {:user => user})
load_favourite_page_or_index
#redirect_back_or_default my_page_path
end
def load_favourite_page_or_index
user = User.current
favourite_page_field = CustomField.where(name: ["Favourite page", "favourite page", "favorite page", "Favourite page", "Любимая страница", "любимая страница", "Избранная страница", "избранная страница"]).first
page_url = user.custom_values.where(custom_field_id: favourite_page_field.id).first.value
if page_url.empty?
redirect_back_or_default my_page_path
else
redirect_to(page_url)
end
end
def self.hello
puts "Hello"
end
end
end
end
只有在使用模块混合模式时,class 方法才真正需要使用单独的模块。在使用单独的 InstanceMethods 模块的框架代码中,可用于组织目的。但在一个简单的 monkeypatch 中,它只会变得更乱。
# config/initializers/my_monkey_patch.rb
# You should explicity require classes in initializers
require Rails.root.join('path', 'to', 'monkeypatch')
require Rails.root.join('path', 'to', 'target')
::AccountController.prepend RedmineKapDesign::Patches::AccountControllerPatch
我有一个AccountControllerclass,这个控制器class在应用程序内核中。我不想更改内核,因此我打算使用 Monkey Patch。 控制器具有名为 successful_authentication 的方法,我已将其重写。在新方法(在我的模块中)中,此代码调用名为 load_favourite_or_index.
的新方法我了解到 alias_method_chain 现在已弃用,不应再使用。我试图在 AccountController 之前 prepend 我的模块。但是没有任何反应,我想我的前置代码不正确,请你帮帮我好吗?这是我的代码。
# frozen_string_literal: true
module RedmineKapDesign
module Patches
module AccountControllerPatch
def self.prepended(base) # :nodoc:
class << base
prepend InstanceMethods
end
end
module InstanceMethods
def successful_authentication(user)
logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
# Valid user
self.logged_user = user
logger.info "Setting.autologin? = #{Setting.autologin?}, params[:autologin] = #{params[:autologin]}"
# generate a key and set cookie if autologin
if params[:autologin] && Setting.autologin?
set_autologin_cookie(user)
end
call_hook(:controller_account_success_authentication_after, {:user => user})
load_favourite_page_or_index
#redirect_back_or_default my_page_path
end
def load_favourite_page_or_index
user = User.current
favourite_page_field = CustomField.where(name: ["Favourite page", "favourite page", "favorite page", "Favourite page", "Любимая страница", "любимая страница", "Избранная страница", "избранная страница"]).first
page_url = user.custom_values.where(custom_field_id: favourite_page_field.id).first.value
if page_url.empty?
redirect_back_or_default my_page_path
else
redirect_to(page_url)
end
end
def self.hello
puts "Hello"
end
end
end
end
end
#unless AccountController.included_modules.include?(RedmineKapDesign::Patches::AccountControllerPatch)
# AccountController.send(:prepend, RedmineKapDesign::Patches::AccountControllerPatch)
#end
AccountController.singleton_class.prepend(RedmineKapDesign::Patches::AccountControllerPatch)
您不需要将实例方法分离到一个单独的模块中。您可以将它们放在 AccountControllerPatch 中并添加任何 class 您正在使用它进行猴子修补的内容。
module RedmineKapDesign
module Patches
module AccountControllerPatch
def successful_authentication(user)
logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
# Valid user
self.logged_user = user
logger.info "Setting.autologin? = #{Setting.autologin?}, params[:autologin] = #{params[:autologin]}"
# generate a key and set cookie if autologin
if params[:autologin] && Setting.autologin?
set_autologin_cookie(user)
end
call_hook(:controller_account_success_authentication_after, {:user => user})
load_favourite_page_or_index
#redirect_back_or_default my_page_path
end
def load_favourite_page_or_index
user = User.current
favourite_page_field = CustomField.where(name: ["Favourite page", "favourite page", "favorite page", "Favourite page", "Любимая страница", "любимая страница", "Избранная страница", "избранная страница"]).first
page_url = user.custom_values.where(custom_field_id: favourite_page_field.id).first.value
if page_url.empty?
redirect_back_or_default my_page_path
else
redirect_to(page_url)
end
end
def self.hello
puts "Hello"
end
end
end
end
只有在使用模块混合模式时,class 方法才真正需要使用单独的模块。在使用单独的 InstanceMethods 模块的框架代码中,可用于组织目的。但在一个简单的 monkeypatch 中,它只会变得更乱。
# config/initializers/my_monkey_patch.rb
# You should explicity require classes in initializers
require Rails.root.join('path', 'to', 'monkeypatch')
require Rails.root.join('path', 'to', 'target')
::AccountController.prepend RedmineKapDesign::Patches::AccountControllerPatch