ruby-on-rails - Ruby gem 方法仅在控制器中可用?如果是这样,如何使其在其他文件中可用?
问题描述
我的印象是,一旦使用 bundler 安装 gem 的方法,就可以在 Rails 应用程序的任何地方访问它。但事实并非如此吗?我很困惑,因为controller
当移出文件时无法识别其中可访问的方法。有什么方法可以要求 gem 在command
文件中运行下面的代码而不是controller
?
我正在使用一个名为sorcery
来实现 OAuth 登录系统的身份验证 gem。有一些类似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:>)
提前致谢。
解决方案
我的印象是,一旦使用 bundler 安装 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
是使用其他sorcery
方法和继承自ActionController::Base
. 因此,您需要确保所有这些方法都可用Authentication::LoginCommand
才能login_from
正常运行。
推荐阅读
- python - 未创建 SparkContext 对象
- python - 删除 Python 中的空行和注释(不带正则表达式)
- sql - 我需要在一个表的一部分中按规范条件选择行
- r - 如何根据R中分隔符之间的出现替换字符串中的确切字符数
- php - 如何从另一台服务器执行一个可爱的 json?
- c# - 根据条件 C# 比较两个列表
- php - 为什么 $http_response_header 总是为空?
- c++ - 未能通过 shared_ptr
作为 shared_ptr 参考 - javascript - 散景 - 如何创建可隐藏的侧边栏
- python - 使用 train_test_split 拆分数据时与之后加载 csv 文件的精度不同