Rails&Rolify:创建时添加默认角色?

3

目前我正在使用Rolify & CanCan来管理我的Rails 3应用程序中的角色和能力。我的问题是:如何在创建时使用户默认拥有一个角色?例如,如果我有一个“用户”角色,如何使所有在我的应用程序中注册的用户默认拥有用户角色?我的Ability.rb文件有以下代码:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.has_role? :admin
      can :manage, :all
    elsif user.has_role? :user
      can :update, User, :id => user.id
    end
  end
end

我的用户模型有这个:

class User < ActiveRecord::Base
  rolify
  authenticates_with_sorcery!
  attr_accessible :username, :email, :password, :password_confirmation

  validates_confirmation_of :password
  validates_presence_of :password, :on => :create
  validates_presence_of :username
  validates_uniqueness_of :username
  validates_presence_of :email
  validates_uniqueness_of :email
end
榜样就是这个:
class Role < ActiveRecord::Base
  has_and_belongs_to_many :users, :join_table => :users_roles
  belongs_to :resource, :polymorphic => true
end

UsersController中,我们有:

def new
  @user = User.new
end

def create
  @user = User.new(params[:user])

  if @user.save
    redirect_to users_path, :notice => "Tu usuario se ha guardado"
  else
    render "new"
  end
end

最后,Rolify 迁移 就是这个:

class RolifyCreateRoles < ActiveRecord::Migration
  def change
    create_table(:roles) do |t|
      t.string :name
      t.references :resource, :polymorphic => true

      t.timestamps
    end

    create_table(:users_roles, :id => false) do |t|
      t.references :user
      t.references :role
    end

    add_index(:roles, :name)
    add_index(:roles, [ :name, :resource_type, :resource_id ])
    add_index(:users_roles, [ :user_id, :role_id ])
  end
end

现在,我可以通过使用 Rails控制台手动分配角色:
1 User.all
2 User.find(id)
3 User.add_role(:role)

当每个用户被创建时,如何自动分配默认角色呢?
谢谢!
4个回答

23

你可以使用一个Active Record回调函数在用户创建后分配角色。类似下面的代码:

class User < ActiveRecord::Base
  after_create :assign_default_role

  def assign_default_role
    add_role(:role)
  end
end

请注意,还有一个 after_save 回调函数,但它每次保存用户时都会被调用。因此,如果您编辑用户并保存,它将尝试再次添加角色。这就是为什么我改用 after_create 回调函数。


这也是一个好的解决方案!;) - Jmlevick
1
太棒了!省去了我很多烦恼。 - ezuk
在执行 add_role 前最好先检查是否已经分配了角色。 - Cam Song
1
@CamSong 但这是一个 after_create 回调,所以不需要检查。 - Dty

7

在使用add_role之前最好检查是否已分配了角色,因此我更喜欢:

class User < ActiveRecord::Base
  after_create :assign_default_role

  def assign_default_role
    add_role(:normal) if self.roles.blank?
  end
end

1
这是 after_create,不应该有其他角色。 - pferrel

3
忘了它,只需要添加:

@user.add_role(:user)

在我的创建操作中,在@user = User.new(params[:user])行的后面。

我自己想出来了...我还在学习 :)

谢谢!


7
你正在控制器中执行这个操作,这不是正确的操作位置。像这样的逻辑应该放在模型中。俗话说“控制器瘦身,模型臃肿”。在模型中执行此操作还可以让你进行单元测试,而不是控制器测试。 - Dty
1
Dty有一点是正确的。你想要它变得DRY。任何创建用户的控制器/操作都必须有这行代码。通过在模型中使用after_create回调放置它,你使它变得DRY了。 - Ely
为什么不把它放在迁移中呢?像这样: def change change_column :users, :role, :integer, :default => 'user' end然后当使用devise创建用户时,默认情况下它将成为“用户”角色。 - karlihnos

2
after_create :default_role

private
  def default_role
    self.roles << Role.find_by_name("user")
    self.save
  end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接