CanCan Отдельная ролевая модель - PullRequest
3 голосов
/ 14 июня 2011

Я следовал этому руководству по реализации Отдельной ролевой модели в CanCan .Когда User, пытается зарегистрироваться, эта ошибка выдается при создании Assignment.

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

Я использую сгенерированный Devise User со следующими before_save функциями

class User < ActiveRecord::Base
.
.
.
 def create_profile
    profile = Profile.new :user_id => :id
  end

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

Я хочу по умолчанию роль пользователя "пользователь ", но я явно что-то делаю не так.Как это должно быть реализовано?

Ответы [ 4 ]

9 голосов
/ 14 июня 2011

Не уверен, видели ли вы это или нет, но Райан Бейтс подготовил замечательный документ, касающийся:

отдельных ролевых моделей

РЕДАКТИРОВАТЬ:

Вот что я сейчас использую.Я считаю, что ваше «Назначение» совпадает с моим «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 << [role_name], я по сути создаю UserRole, в которой есть user_id и role_id. </p>

3 голосов
/ 14 июня 2011

Могут быть и более эффективные способы сделать это, но я не могу сказать без точных ассоциаций моделей.

В любом случае, я думаю, что это должно работать:

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

Поскольку вы указываете: user, а не: user_id, вы должны передать self.То же самое для: роль.Если вы указали: role_id, то вы должны были ввести .id после find_by_role, но так как вы указали только: role, тогда удалите .id

2 голосов
/ 14 июня 2011

Во-первых, вы не должны использовать функцию обратного вызова save, потому что она будет запущена как при создании, так и при обновлении.

Во-вторых, если вы устанавливаете ассоциации между моделями, как это:будет иметь удобные методы, такие как user.profile, user.build_profile и user.create_profile.Build & Create автоматически настроит user_id в профиле.Вы можете использовать их в своих обратных вызовах без необходимости определения каких-либо методов.

Обратите внимание, что перед сохранением пользователя у него нет идентификатора.Так что вам нужно использовать либо before_create :build_profile либо after_create :create_profile.Первый создаст профиль в памяти, который будет автоматически сохранен после сохранения пользователя, второй довольно прост.

Будут аналогичные методы для назначений: user.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
2 голосов
/ 14 июня 2011

Похоже, вы передаете символы в условия хеширования, которые ожидают объекты.

Ответ DanneManne должен работать. Вы могли бы альтернативно сделать

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

(но Данна лучше, имо)

Последнее предложение - почему бы не сказать, что роль называется «имя», а не «роль». Итак, вы будете делать, Role.find_by_name ('user'). Последующему программисту было бы легче следовать за этим.

...