2013-11-19 2 views
3

Это странно. Я использую Rolify + CanCan + Devise в приложении rails 3.2. Мой пример использования прост. Я хочу, чтобы пользователь имеет только один роль в то время, таким образом, чтобы изменить свою роль, я сделать что-то вроде этого:Удалить удаление из таблицы ролей?

user.remove_role "admin" 
user.add_role "associate" 

Странное мне в том, что когда я делаю это, роль «администратор» получает удалены из таблицы Роли. Почему это должно быть? Я не хочу полностью исключать эту роль, только определенную роль от пользователя. Что я делаю не так?

Вот SQL. Обратите внимание на последнее удаление из ролей высказывания:

3] pry(main)> u.remove_role "sub_admin" 
    Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = 2 AND "roles"."name" = 'sub_admin' 
    (0.0ms) begin transaction 
    (0.3ms) DELETE FROM "users_roles" WHERE "users_roles"."user_id" = 2 AND "users_roles"."role_id" IN (2) 
    (1.9ms) commit transaction 
    User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "users_roles" ON "users"."id" = "users_roles"."user_id" WHERE "users_roles"."role_id" = 2 
    (0.0ms) begin transaction 
    SQL (2.1ms) DELETE FROM "roles" WHERE "roles"."id" = ? [["id", 2]] 
    (0.6ms) commit transaction 

ответ

3

Основная проблема заключается в том, что каждую комбинацию, если имя роль, resource_type и resource_id хранятся только один раз в roles таблицы. Если вы удалите эту строку, она будет удалена для всех.

Решение заключается в том, чтобы удалить только строки из join table, которые соединяют модели User и Role. Для удобства доступа я сделаю таблицу объединений моделью, чтобы использовать некоторую магию рельсов для генерации SQL. Поскольку это действительно своего рода объект службы, я сделаю его одним сингл-классом. Вот мой хак:

class UsersRoles < ActiveRecord::Base 

    def self.delete_role(subject,role_symbol, obj=nil) 
     res_name = obj.nil? ? nil : obj.class.name 
     res_id = obj.id rescue nil 
     role_row = subject.roles.where(name: role_symbol.to_s, resource_type: res_name , resource_id: res_id).first 
     if role_row.nil? 
      raise "cannot delete nonexisting role on subject" 
     end 
     role_id = role_row.id 
     self.delete_all(user_id: subject.id,role_id: role_id) 
    end 

    private_class_method :new 
end 

Этот код не оптимизирован, но должно дать вам представление, что делать: например, теперь вы можете добавить удобный метод для User модели:

def delete_role(role_symbol,target=nil) 
    UsersRoles.delete_role self,role_symbol,target 
end 

затем вы можете сказать:

user.delete_role :admin 

и он удалит только то, что вы хотите.

Обратите внимание, что это не будет удалите строку таблицы с ролью, которую я сохраню для использования в будущем.

+0

Где я могу это поставить? Как новый контроллер? –

+0

Это не новый контроллер, а Active Recrod Model для таблицы соединений, который обычно не имеет этого. – semiomant

1

Я знаю, что этот вопрос более двух лет, но я нашел лучше и более «откат».
Вы можете сделать это очень легко в модели пользователя:

def remove_only_role_relation(role_name) 
    roles.delete(roles.where(:name => role_name)) 
end 

и использовать его как:

@user = User.find_by_id(params[:id]) 
role_name = params[:role_name] 
# or: 
# role_name = Role.find_by_id(params[:role_id]).name rescue nil 
if @user and role_name 
    @user.remove_only_role_relation(role_name) 
end 

Я нашел подобный код в своих источниках:
rolyfi: role.rb - здесь метод remove_role метод CALS «удалить "в файле адаптера: rolyfi: role_adapter.rb

0

Вот как я разрешил эту проблему:

модели/user.rb

def delete_roles 
    roles.delete(roles.where(:id => self.roles.ids)) 
end 

user_controller.rb

def add_role 
    @user.delete_roles 
    role = params[:user][:roles] 
    @user.add_role Role.find(role).name if not role.blank? 
    @user.role_id = Role.find(role).id if not role.blank? 
end 

Каждый раз, когда пользователь будет создан или обновлен, удалить роли пользователя.

 Смежные вопросы

  • Нет связанных вопросов^_^