Как правильно добавить модуль в класс? - PullRequest
0 голосов
/ 03 февраля 2020

У меня есть класс AccountController , этот класс контроллера находится в ядре приложения. Я не хочу вносить изменения в ядро, поэтому я собираюсь установить Monkey Patch. У контроллера есть метод с именем success_authentication , который я переписал. Внутри нового метода (в моем модуле) этот код вызывает новый метод с именем load_favourite_or_index .

Я читал, что alias_method_chain сейчас устарела и не должна использоваться. Я пытаюсь добавить мой модуль до AccountController . Но ничего не происходит, я думаю, что мой предварительный код неверен, пожалуйста, не могли бы вы мне помочь? Вот мой код.

# 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)

1 Ответ

1 голос
/ 03 февраля 2020

Вам не нужно выделять методы экземпляра в отдельный модуль. Вы можете просто поместить их в AccountControllerPatch и добавить к нему любой класс, к которому вы добавляете обезьяны.

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

Использование отдельного модуля действительно необходимо только для методов класса при использовании шаблона mixin модуля. В программном коде с использованием отдельного модуля InstanceMethods можно использовать для организационных целей. Но в простом обезьяньем патче это просто создает беспорядок.

# 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
...