【问题标题】:rails devise undefined method username when I want to use it with cancancan当我想将它与cancancan一起使用时,rails会设计未定义的方法用户名
【发布时间】:2017-01-05 10:14:55
【问题描述】:

我想在 Rails 中实现基于角色的授权。对于登录,我使用 gem 设计,效果很好。但是在我在 tutorial 中包含一些 cancancan 的代码后,我收到一个错误未定义的方法用户名,当我删除用户名时,我收到一个错误未定义的方法电子邮件...

这是我的代码:

ability.rb(管理具有特定角色的用户可以做什么)

    class Ability

  include CanCan::Ability

  def initialize(user)

      user ||= User.new

     if user.role?(:admin)
       can :manage, :all
     elsif user.role?(:mitarbeiter)
       can :manage, :documents
       can :manage, :entries
     end

  end

end

我的 user.rb 的一部分

      ROLES = {0 => :admin, 1 => :mitarbeiter}

  attr_reader :role :

  def initialize(role_id = 0)
    @role = ROLES.has_key?(role_id) ? ROLES[role_id] : ROLES[0]

  end

  def role?(role_name)
    role == role_name
  end

我的 application_controller.rb 的一部分

  protect_from_forgery with: :exception

  check_authorization

  rescue_from CanCan::AccessDenied do |exception|
    flash[:warning] = exception.message
    redirect_to root_path
  end

  private

  def current_user
    User.new(session[:id])
  end

  helper_method :current_user

我真的不明白怎么回事... 我以为我必须在 user.rb 中设置 @user 之类的 @role 但它没有帮助

【问题讨论】:

  • 这个错误发生在哪里 - 你没有在你的问题的任何地方调用username
  • 啊,对不起,我在视图中调用 current_user.username。在我使用 cancancan 之前,它确实有效......
  • 我认为你不应该为 ActiveRecord 派生的模型覆盖 initialize,至少在不调用 super 的情况下是这样。

标签: ruby-on-rails ruby devise cancan cancancan


【解决方案1】:

我找到了解决方案,并且 role_id 也正确存储在数据库中。这是我的解决方案:

我的新能力.rb(未完成仅用于测试功能)

    class Ability

  include CanCan::Ability

  def initialize(user)

     user ||= User.new

     if user.has_role? :admin
       can :manage, :all
     elsif user.has_role? :mitarbeiter
       can :manage, :documents
       can :manage, :entries
     else
        can :read, :all
     end

  end

end

新用户.rb

      ROLES = %i[admin mitarbeiter]

  def roles=(roles)
    roles = [*roles].map { |r| r.to_sym }
    self.role_id = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
  end

  def roles
    ROLES.reject do |r|
      ((role_id.to_i || 0) & 2**ROLES.index(r)).zero?
    end
  end

  def has_role?(role)
    roles.include?(role)
  end

新的 application_controller.rb 部分

  def configure_permitted_parameters
    added_attrs = [:username, :email, :password, :password_confirmation, :remember_me, roles: [] ]
    devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
    devise_parameter_sanitizer.permit :account_update, keys: added_attrs
  end

这里我将角色赋予用户views/devise/registrations/new.html.erb

    <% for role in User::ROLES %>
      <%= check_box_tag "user[roles][#{role}]", role, @user.roles.include?(role), {:name => "user[roles][]"}%>
      <%= label_tag "user_roles_#{role}", role.to_s.humanize %><br />
    <% end %>
    <%= hidden_field_tag "user[roles][]", "" %>

我还删除了一些可能是问题的 gem(回形针、roo、rolify) 我在我的 Gemfile 中得到了这个:

    gem 'devise', github: 'plataformatec/devise'
    gem 'cancancan'

【讨论】:

    【解决方案2】:

    我建议删除User#initialize 方法和attr_reader :role 声明并创建自己的role 方法,如下所示:

    def role
      @role ||= ROLES.has_key?(role_id) ? ROLES[role_id] : ROLES[0]
    end
    
    def role?(role_name)
      role == role_name
    end
    

    这样你就可以实现你想要的,但不会覆盖 ActiveRecord 的 User#initialize 方法。

    以上代码假定role_id 存储在数据库中的role_id 列中。

    【讨论】:

    • 我认为需要初始化方法来设置角色可以做什么,或者我在这里错了吗?
    • 我得到这个错误:未定义的局部变量或方法`role_id'
    • 必须以某种方式存储用户角色?您是否将role_id 存储在数据库中?
    • 不,我在用户表中有一个“角色”字段,但角色没有存储在数据库中。有问题吗?
    • 您不需要特殊的表来存储用户的角色。您需要用户表中的一列。 IMO 数字类型role_id(或任何其他名称),当用户为管理员时,您将在其中存储0,当用户为mitarbeiter 时存储1
    猜你喜欢
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2019-06-24
    • 2015-11-24
    • 2014-07-31
    • 2018-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多