Ruby on rails 用作用域用户模型设计不可侵犯的邀请令牌

Ruby on rails 用作用域用户模型设计不可侵犯的邀请令牌,ruby-on-rails,devise,ruby-on-rails-5,devise-invitable,Ruby On Rails,Devise,Ruby On Rails 5,Devise Invitable,我有一个用户模型,其作用域是站点id。当Desive尝试通过令牌查找受邀请的用户时,站点id不包括在内 class User < ApplicationRecord belongs_to :site default_scope { where(site_id: Site.current_id) } devise :invitable, :confirmable, :database_authenticatable, :registerable, :recoverable, :rememb

我有一个用户模型,其作用域是站点id。当Desive尝试通过令牌查找受邀请的用户时,站点id不包括在内

class User < ApplicationRecord

belongs_to :site
default_scope { where(site_id: Site.current_id) }
devise :invitable, :confirmable, :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable

  validates_uniqueness_of :email, scope: :site
  validates_format_of :email, with: Devise::email_regexp

end

如何使Deviate能够识别用户范围?

我的方法是覆盖邀请\u controller.rb。我查看了designe_invitable()内置的默认邀请\u controller.rb,并调整了before_操作

routes.rb

devise_for :users, controllers: { invitations: 'users/invitations' }
/app/controllers/users/investments\u controller.rb

class Users::InvitationsController < Devise::InvitationsController

    skip_before_action :resource_from_invitation_token, only: [:edit]
    before_action :scoped_resource_from_invitation_token, only: [:edit]

    private
    def scoped_resource_from_invitation_token

        unless params[:invitation_token] && self.resource = User.find_by_invitation_token(params[:invitation_token], true)
            set_flash_message(:alert, :invitation_token_invalid) if is_flashing_format?
            redirect_to after_sign_out_path_for(resource_name)
        end

    end

end

# self.resource = resource_class.find_by_invitation_token

# is now

# self.resource = User.find_by_invitation_token
class用户::invitationcontroller
更详细地说:

class Users::InvitationsController < Devise::InvitationsController

  skip_before_action :has_invitations_left?, :only => [:create]
  skip_before_action :resource_from_invitation_token, :only => [:edit, :destroy]

  before_action :scoped_has_invitations_left?, :only => [:create]
  before_action :scoped_resource_from_invitation_token, :only => [:edit, :destroy]

  if respond_to? :helper_method
    helper_method :after_sign_in_path_for
  end

  # GET /resource/invitation/new
  def new
    self.resource = User.new
    render :new
  end

  # POST /resource/invitation
  def create
    self.resource = invite_resource
    resource_invited = resource.errors.empty?

    yield resource if block_given?

    if resource_invited
      if is_flashing_format? && self.resource.invitation_sent_at
        set_flash_message :notice, :send_instructions, :email => self.resource.email
      end
      if self.method(:after_invite_path_for).arity == 1
        respond_with resource, :location => after_invite_path_for(current_inviter)
      else
        respond_with resource, :location => after_invite_path_for(current_inviter, resource)
      end
    else
      respond_with_navigational(resource) { render :new }
    end
  end

  # GET /resource/invitation/accept?invitation_token=abcdef
  def edit
    set_minimum_password_length
    resource.invitation_token = params[:invitation_token]
    render :edit
  end

  # PUT /resource/invitation
  def update
    raw_invitation_token = update_resource_params[:invitation_token]
    self.resource = accept_resource
    invitation_accepted = resource.errors.empty?

    yield resource if block_given?

    if invitation_accepted
      if Devise.allow_insecure_sign_in_after_accept
        flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
        set_flash_message :notice, flash_message if is_flashing_format?
        sign_in(resource_name, resource)
        respond_with resource, :location => after_accept_path_for(resource)
      else
        set_flash_message :notice, :updated_not_active if is_flashing_format?
        respond_with resource, :location => new_session_path(resource_name)
      end
    else
      resource.invitation_token = raw_invitation_token
      respond_with_navigational(resource){ render :edit }
    end
  end

  # GET /resource/invitation/remove?invitation_token=abcdef
  def destroy
    resource.destroy
    set_flash_message :notice, :invitation_removed if is_flashing_format?
    redirect_to after_sign_out_path_for(resource_name)
  end

  protected

  def invite_resource(&block)
    User.invite!(invite_params, current_inviter, &block)
  end

  def accept_resource
    User.accept_invitation!(update_resource_params)
  end

  def current_inviter
    authenticate_inviter!
  end

  def scoped_has_invitations_left?
    unless current_inviter.nil? || current_inviter.has_invitations_left?
      self.resource = User.new
      set_flash_message :alert, :no_invitations_remaining if is_flashing_format?
      respond_with_navigational(resource) { render :new }
    end
  end

  def scoped_resource_from_invitation_token
    unless params[:invitation_token] && self.resource = User.find_by_invitation_token(params[:invitation_token], true)
      set_flash_message(:alert, :invitation_token_invalid) if is_flashing_format?
      redirect_to after_sign_out_path_for(resource_name)
    end
  end

  def invite_params
    devise_parameter_sanitizer.sanitize(:invite)
  end

  def update_resource_params
    devise_parameter_sanitizer.sanitize(:accept_invitation)
  end

  def translation_scope
    'devise.invitations'
  end
end
class用户::invitationcontroller[:创建]
在\u操作之前跳过\u:来自\u邀请\u令牌的资源\u,:only=>[:编辑,:销毁]
在\u操作之前:作用域\u还有\u邀请吗?,:only=>[:create]
在\u操作之前:来自\u邀请\u令牌的作用域\u资源,:only=>[:编辑,:销毁]
如果您有任何回应:辅助法
helper\u方法:在为
结束
#获取/资源/邀请/新建
def新
self.resource=User.new
渲染:新
结束
#职位/资源/邀请
def创建
self.resource=邀请资源
resource\u invested=resource.errors.empty?
如果给定块,是否产生资源?
如果资源被邀请
如果是闪烁格式?&&self.resource.investment\u已发送到
设置\u flash\u消息:通知,:发送\u说明,:email=>self.resource.email
结束
if self.method(:after\u invite\u path\u for).arity==1
使用资源响应(当前邀请者):位置=>在邀请路径之后
其他的
使用资源响应(当前邀请者,资源)
结束
其他的
用导航(资源){render:new}响应
结束
结束
#获取/资源/邀请/接受?邀请\u令牌=abcdef
定义编辑
设置\u最小\u密码\u长度
resource.invitation\u token=参数[:invitation\u token]
渲染:编辑
结束
#放置/资源/邀请
def更新
原始邀请令牌=更新资源参数[:邀请令牌]
self.resource=接受资源
邀请被接受=resource.errors.empty?
如果给定块,是否产生资源?
如果你接受邀请
如果设计不安全,请在接受后签名
flash\u message=resource.active\u用于\u身份验证??:已更新::已更新\u未激活
设置闪光信息:注意,闪光信息是否为闪光信息格式?
登录(资源名称、资源)
使用资源响应:location=>after\u accept\u path\u for(资源)
其他的
设置闪烁消息:注意:如果是闪烁格式,则更新的闪烁消息未激活?
使用资源响应:location=>新建会话路径(资源名称)
结束
其他的
resource.invitation\u token=原始邀请\u token
用导航(资源){render:edit}响应
结束
结束
#获取/资源/邀请/删除?邀请\u令牌=abcdef
def销毁
资源破坏
设置\u flash \u消息:注意,:如果是\u flash \u格式,则邀请\u已删除?
将\u重定向到\u注销后\u路径\u(资源\u名称)
结束
受保护的
def invite_资源(&block)
User.invite!(邀请参数、当前邀请者和阻止)
结束
def接受_资源
User.accept_邀请!(更新资源参数)
结束
def当前邀请器
认证邀请者!
结束
def scoped_还有邀请吗?
除非是当前邀请者。无当前邀请者已离开邀请吗?
self.resource=User.new
设置\u flash \u消息:警报,如果为\u flash \u格式,则没有剩余的\u邀请?
用导航(资源){render:new}响应
结束
结束
来自邀请令牌的定义范围的资源
除非参数[:invitation\u token]&&self.resource=User.find\u by\u invitation\u token(参数[:invitation\u token],true)
如果是闪烁格式,则设置闪烁消息(:警报,:邀请\u令牌\u无效)?
将\u重定向到\u注销后\u路径\u(资源\u名称)
结束
结束
def invite_参数
设计\u参数\u消毒液。消毒(:invite)
结束
def更新资源参数
设计\u参数\u消毒液。消毒(:接受邀请)
结束
def翻译范围
“设计邀请”
结束
结束

您必须重新审视在用户模型内部使用
Site.id
的解决方案。你能告诉我更多关于object
Site
class Users::InvitationsController < Devise::InvitationsController

  skip_before_action :has_invitations_left?, :only => [:create]
  skip_before_action :resource_from_invitation_token, :only => [:edit, :destroy]

  before_action :scoped_has_invitations_left?, :only => [:create]
  before_action :scoped_resource_from_invitation_token, :only => [:edit, :destroy]

  if respond_to? :helper_method
    helper_method :after_sign_in_path_for
  end

  # GET /resource/invitation/new
  def new
    self.resource = User.new
    render :new
  end

  # POST /resource/invitation
  def create
    self.resource = invite_resource
    resource_invited = resource.errors.empty?

    yield resource if block_given?

    if resource_invited
      if is_flashing_format? && self.resource.invitation_sent_at
        set_flash_message :notice, :send_instructions, :email => self.resource.email
      end
      if self.method(:after_invite_path_for).arity == 1
        respond_with resource, :location => after_invite_path_for(current_inviter)
      else
        respond_with resource, :location => after_invite_path_for(current_inviter, resource)
      end
    else
      respond_with_navigational(resource) { render :new }
    end
  end

  # GET /resource/invitation/accept?invitation_token=abcdef
  def edit
    set_minimum_password_length
    resource.invitation_token = params[:invitation_token]
    render :edit
  end

  # PUT /resource/invitation
  def update
    raw_invitation_token = update_resource_params[:invitation_token]
    self.resource = accept_resource
    invitation_accepted = resource.errors.empty?

    yield resource if block_given?

    if invitation_accepted
      if Devise.allow_insecure_sign_in_after_accept
        flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
        set_flash_message :notice, flash_message if is_flashing_format?
        sign_in(resource_name, resource)
        respond_with resource, :location => after_accept_path_for(resource)
      else
        set_flash_message :notice, :updated_not_active if is_flashing_format?
        respond_with resource, :location => new_session_path(resource_name)
      end
    else
      resource.invitation_token = raw_invitation_token
      respond_with_navigational(resource){ render :edit }
    end
  end

  # GET /resource/invitation/remove?invitation_token=abcdef
  def destroy
    resource.destroy
    set_flash_message :notice, :invitation_removed if is_flashing_format?
    redirect_to after_sign_out_path_for(resource_name)
  end

  protected

  def invite_resource(&block)
    User.invite!(invite_params, current_inviter, &block)
  end

  def accept_resource
    User.accept_invitation!(update_resource_params)
  end

  def current_inviter
    authenticate_inviter!
  end

  def scoped_has_invitations_left?
    unless current_inviter.nil? || current_inviter.has_invitations_left?
      self.resource = User.new
      set_flash_message :alert, :no_invitations_remaining if is_flashing_format?
      respond_with_navigational(resource) { render :new }
    end
  end

  def scoped_resource_from_invitation_token
    unless params[:invitation_token] && self.resource = User.find_by_invitation_token(params[:invitation_token], true)
      set_flash_message(:alert, :invitation_token_invalid) if is_flashing_format?
      redirect_to after_sign_out_path_for(resource_name)
    end
  end

  def invite_params
    devise_parameter_sanitizer.sanitize(:invite)
  end

  def update_resource_params
    devise_parameter_sanitizer.sanitize(:accept_invitation)
  end

  def translation_scope
    'devise.invitations'
  end
end