CanCan独立角色模型

时间:2011-06-14 02:49:26

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

我一直关注this中关于单独角色模型实施的CanCan指南。当User尝试注册时,会在创建Assignment时抛出此错误。

User(#21477600) expected, got Symbol(#5785720)

我正在使用带有以下User函数的<{1}}生成的Devise

before_save

我想将用户的角色默认为“用户”,但我显然做错了什么。该如何实施?

4 个答案:

答案 0 :(得分:9)

不确定您是否看过这个,但Ryan Bates制作了一份精彩的文件:

Separate Role Models

编辑:

这是我目前正在使用的内容。我相信你的'作业'与我的'UserRole'相同。

user.rb

#--
# Relationship
has_many :user_roles, :dependent => :destroy, :uniq => true
has_many :roles, :through => :user_roles, :uniq => true

#--
# Instance Method

# Determine if the user has a specified role
# You can find this method at: https://github.com/ryanb/cancan/wiki/Separate-Role-Model
# Written by Ryan Bates, I added the downcase though to detect 'Admin' vs 'admin'.
# Example:
#       user.has_role? :Admin
#       => true
def has_role?(role_sym)
  roles.any? { |role| role.name.underscore.to_sym == role_sym.downcase }
end

role.rb

#  id         :integer(4)      not null, primary key
#  name       :string(255)  

#--
# Relationship
has_many :user_roles, :dependent => :destroy, :uniq => true
has_many :users, :through => :user_roles, :uniq => true

user_role.rb

#  id         :integer(4)      not null, primary key
#  user_id    :integer(4)
#  role_id    :integer(4)

#--
# Relationship
belongs_to :user
belongs_to :role

然后在我的能力.rb

def initialize(user)
  user ||= User.new                   # in case of a guest
  if user.has_role? :Admin            # The user is an Administrator
    can :manage, :all
  else
    can :read, :all
  end
end

然后我可以通过执行以下操作轻松分配角色,例如在我的种子文件中:

# Create Users
...

# Roles
admin = Role.create!(:name => "admin")
standard = Role.create!(:name => "standard")

# UserRoles :Admin
user1.roles << admin
user2.roles << standard

所以通过调用user.roles&lt;&lt; [role_name],我实际上是在创建一个UserRole,它有一个user_id和一个role_id。

答案 1 :(得分:3)

可能有一些更有效的方法可以实现这一目标,但我不知道没有确切的模型关联。

无论如何,我认为这应该有效:

def create_role
  Assignment.new :user => self, :role => Role.find_by_role("user")
end

由于您指定:user而不是:user_id,您应该传递self。同样的事情:角色。如果您指定了:role_id,那么您应该在find_by_role之后输入.id但是因为您只指定:role然后删除.id

答案 2 :(得分:2)

看起来你正在将符号传递给期望对象的哈希条件。

DanneManne的回答应该有效。你也可以做

Assignment.new( :user_id=>self.id, :role_id => Role.find_by_role('user').id )

(但Danne's更好,imo)

最后一个建议 - 为什么不说角色的名字是“名字”,而不是“角色”。所以你要做的就是Role.find_by_name('user')。对于后来的程序员来说,这会更容易。

答案 3 :(得分:2)

首先,你不应该使用save回调,因为它将同时在create&amp;更新

其次,如果你在这样的模型之间建立关联:

class User < ActiveRecord::Base
  has_one :profile
  has_many :assignments
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

class Assignment < ActiveRecord::Base
  belongs_to :user
  belongs_to :role
end

您将拥有方便的方法,例如user.profileuser.build_profileuser.create_profile。建设与发展创建将自动在个人资料上设置user_id。您可以在回调中使用它们,而无需定义任何方法。

请注意,在保存用户之前,它没有ID。因此,您需要使用before_create :build_profile after_create :create_profileuser.assignments.build。第一个将在内存中创建配置文件,在用户保存后将自动保存,第二个非常简单。

也会有类似的作业方法:user.assignments.create class User < ActiveRecord::Base has_one :profile has_many :assignments after_create :create_profile, :create_assignment def create_assignment assignments.create :role => Role.find_by_role("user") end end 。所以User的最终代码看起来像这样

{{1}}