簡體   English   中英

Ruby gem方法只在控制器中可用? 如果是這樣,如何在其他文件中使用它?

[英]Ruby gem method only available in controller? If so, how to make it available in other files?

我的印象是,一旦用捆綁器安裝了gem的方法,就可以在Rails應用程序中的任何地方訪問它。 但事實並非如此嗎? 我很困惑,因為當移動到文件外時,無法識別controller可訪問的方法。 有什么方法我可以要求gem在command文件而不是controller運行下面的代碼?

我正在使用名為sorcery的身份驗證gem來實現OAuth登錄系統。 有一些方法,比如gem提供的login_from(provider) ,可以從我的控制器訪問就好了。

# app/controllers/oauths_controller.rb
class OauthsController < ApplicationController
  skip_before_action :require_login

  def callback
    provider = params[:provider]
    if @user = login_from(provider)
    # method continues
  end

但是,我們嘗試在我們的應用程序中采用命令查詢分離方法,因此我嘗試將包含login_from(provider)方法的此進程移動到名為app/commands/authentication/login_command.rb的其他文件中。 這導致該方法無法識別:

NoMethodError (undefined method 'login_from' for #<Authentication::LoginCommand:>)

提前致謝。

我的印象是,一旦用捆綁器安裝了gem的方法,就可以在Rails應用程序中的任何地方訪問它。

這將是一個錯誤的印象。

如您所見, Sorcery::Engine使ActionController::Base包含在Sorcery::Controller定義的方法,這里:

require 'sorcery'
require 'rails'

module Sorcery
  # The Sorcery engine takes care of extending ActiveRecord (if used) and ActionController,
  # With the plugin logic.
  class Engine < Rails::Engine
    config.sorcery = ::Sorcery::Controller::Config

    initializer 'extend Controller with sorcery' do
      # TODO: Should this include a modified version of the helper methods?
      if defined?(ActionController::API)
        ActionController::API.send(:include, Sorcery::Controller)
      end

      if defined?(ActionController::Base)
        ActionController::Base.send(:include, Sorcery::Controller)
        ActionController::Base.helper_method :current_user
        ActionController::Base.helper_method :logged_in?
      end
    end
  end
end

Sorcer::Controller依次包含一系列子模塊:

module Sorcery
  module Controller
    def self.included(klass)
      klass.class_eval do
        include InstanceMethods
        Config.submodules.each do |mod|
          # FIXME: Is there a cleaner way to handle missing submodules?
          # rubocop:disable Lint/HandleExceptions
          begin
            include Submodules.const_get(mod.to_s.split('_').map(&:capitalize).join)
          rescue NameError
            # don't stop on a missing submodule.
          end
          # rubocop:enable Lint/HandleExceptions
        end
      end
      Config.update!
      Config.configure!
    end

    ...
  end
end

其中一個子模塊是Sourcery::Controller::Submodules::External ,當包含它時,還包括Sourcery::Controller::Submodules::External::InstanceMethods ,這里:

module Sorcery
  module Controller
    module Submodules
      # This submodule helps you login users from external auth providers such as Twitter.
      # This is the controller part which handles the http requests and tokens passed between the app and the @provider.
      module External
        def self.included(base)
          base.send(:include, InstanceMethods)
          ...
        end
      end
    end
  end
end

而且, InstanceMethods包含login_from方法,這里:

module Sorcery
  module Controller
    module Submodules
      # This submodule helps you login users from external auth providers such as Twitter.
      # This is the controller part which handles the http requests and tokens passed between the app and the @provider.
      module External
        def self.included(base)
          base.send(:include, InstanceMethods)

        module InstanceMethods
          protected

          ...

          # tries to login the user from provider's callback
          def login_from(provider_name, should_remember = false)
            sorcery_fetch_user_hash provider_name

            return unless (user = user_class.load_from_provider(provider_name, @user_hash[:uid].to_s))

            # we found the user.
            # clear the session
            return_to_url = session[:return_to_url]
            reset_sorcery_session
            session[:return_to_url] = return_to_url

            # sign in the user
            auto_login(user, should_remember)
            after_login!(user)

            # return the user
            user
          end

          ...
        end
      end
    end
  end
end

Soooo,這是一個很長的路要說, login_from被定義為繼承自ActionController::Base類的受保護實例方法,並且沒有被定義為不從ActionController::Base繼承的類的實例方法,這就是為什么你'得到NoMethodError

有什么方法我可以要求gem在命令文件而不是控制器中運行下面的代碼?

也許。 也許不吧。 如您所見, login_from正在使用從ActionController::Base繼承的其他sorcery方法和方法。 因此,您需要確保所有這些方法在Authentication::LoginCommand中都可用,以便login_from正常運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM