在设计 SessionsController 和 RegistrationsController 之间创建共享方法的最佳实践
Best practise creating a shared method between devise SessionsController and RegistrationsController
有 3 种方法可以使用邀请令牌进入我的应用程序:
- 您已经登录
- 您有一个帐户,但尚未登录
- 您需要注册
现在我感兴趣的是如何结合 Devise
处理最后两种情况,而不必重复相同的功能。
控制器覆盖由 routes.rb:
处理
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
覆盖会话和注册的 after_sign_in/up_path
:
class Users::SessionsController < Devise::SessionsController
protected
def after_sign_in_path(resource)
handle_invite
super(resource)
end
end
class Users::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
handle_invite
super(resource)
end
end
我应该把handle_invite
方法放在哪里?
我正在寻找一种解决方案,我可以将方法放在我的 UsersController
中,因为那似乎是放置它的正确位置。:
class UsersController < ApplicationController
private
def handle_invite
# Some code getting the token and adding the user to a group
end
end
我认为这应该可行,因为 Devise 似乎继承了这个控制器:
class Users::SessionsController < Devise::SessionsController; end
class Devise::SessionsController < DeviseController; end
class DeviseController < Devise.parent_controller.constantize; end
所以我希望 Devise.parent_controller.constantize
代表 UsersController
,但由于某些原因无法从子控制器调用 handle_invite
。
如果您想使用 classical 继承,您必须通过配置 Devise.parent_controller
将 class 实际放置在继承链中,同时不破坏链的其余部分。
Ruby 没有多重继承。 class 只能继承单亲 class.
# config/initializers/devise.rb
config.parent_controller = 'UsersController'
class UsersController < DeviseController
private
def handle_invite
# Some code getting the token and adding the user to a group
end
end
但这并不是解决问题的最佳方法,因为 Ruby 通过模块进行水平继承:
# app/controllers/concerns/invitable.rb
module Invitable
private
def handle_invite
# Some code getting the token and adding the user to a group
end
def after_sign_in_path(resource)
handle_invite
super(resource)
end
end
# Do not use the scope resolution operator (::) for namespace definition!
# See https://github.com/rubocop-hq/ruby-style-guide#namespace-definition
module Users
class SessionsController < ::Devise::SessionsController
include Invitable
end
end
module Users
class RegistrationsController < ::Devise::SessionsController
include Invitable
end
end
这称为模块混合。在 Java 或 PHP 等其他语言中,它会被称为 特质 。模块封装了一组方法,可以包含在任何class中,也可以将模块混入其他模块中。
在 Rails 术语中,模块混合被称为 concerns
- 这实际上只是包装了一个约定,即 app/controllers/concerns
和 app/models/concerns
目录被添加到自动加载根目录。这意味着 rails 将在那里的顶级命名空间中查找常量。
这也松散地连接到 ActiveSupport::Concern which is syntactic sugar for common ruby idioms。但是没有必要使用它,除非你真的在使用它的功能。
有 3 种方法可以使用邀请令牌进入我的应用程序:
- 您已经登录
- 您有一个帐户,但尚未登录
- 您需要注册
现在我感兴趣的是如何结合 Devise
处理最后两种情况,而不必重复相同的功能。
控制器覆盖由 routes.rb:
处理devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
覆盖会话和注册的 after_sign_in/up_path
:
class Users::SessionsController < Devise::SessionsController
protected
def after_sign_in_path(resource)
handle_invite
super(resource)
end
end
class Users::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
handle_invite
super(resource)
end
end
我应该把handle_invite
方法放在哪里?
我正在寻找一种解决方案,我可以将方法放在我的 UsersController
中,因为那似乎是放置它的正确位置。:
class UsersController < ApplicationController
private
def handle_invite
# Some code getting the token and adding the user to a group
end
end
我认为这应该可行,因为 Devise 似乎继承了这个控制器:
class Users::SessionsController < Devise::SessionsController; end
class Devise::SessionsController < DeviseController; end
class DeviseController < Devise.parent_controller.constantize; end
所以我希望 Devise.parent_controller.constantize
代表 UsersController
,但由于某些原因无法从子控制器调用 handle_invite
。
如果您想使用 classical 继承,您必须通过配置 Devise.parent_controller
将 class 实际放置在继承链中,同时不破坏链的其余部分。
Ruby 没有多重继承。 class 只能继承单亲 class.
# config/initializers/devise.rb
config.parent_controller = 'UsersController'
class UsersController < DeviseController
private
def handle_invite
# Some code getting the token and adding the user to a group
end
end
但这并不是解决问题的最佳方法,因为 Ruby 通过模块进行水平继承:
# app/controllers/concerns/invitable.rb
module Invitable
private
def handle_invite
# Some code getting the token and adding the user to a group
end
def after_sign_in_path(resource)
handle_invite
super(resource)
end
end
# Do not use the scope resolution operator (::) for namespace definition!
# See https://github.com/rubocop-hq/ruby-style-guide#namespace-definition
module Users
class SessionsController < ::Devise::SessionsController
include Invitable
end
end
module Users
class RegistrationsController < ::Devise::SessionsController
include Invitable
end
end
这称为模块混合。在 Java 或 PHP 等其他语言中,它会被称为 特质 。模块封装了一组方法,可以包含在任何class中,也可以将模块混入其他模块中。
在 Rails 术语中,模块混合被称为 concerns
- 这实际上只是包装了一个约定,即 app/controllers/concerns
和 app/models/concerns
目录被添加到自动加载根目录。这意味着 rails 将在那里的顶级命名空间中查找常量。
这也松散地连接到 ActiveSupport::Concern which is syntactic sugar for common ruby idioms。但是没有必要使用它,除非你真的在使用它的功能。