【问题标题】:Rolify remove_role deletes from role table?Rolify remove_role 从角色表中删除?
【发布时间】:2013-11-19 16:23:05
【问题描述】:

这很奇怪。我在我的 rails 3.2 应用程序中使用 Rolify + CanCan + Devise。我的用例很简单。我希望用户一次只有一个角色,因此要更改角色,我会这样做:

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

对我来说奇怪的是,当我这样做时,角色“admin”会从 Roles 表中删除。为什么会这样?我不想完全消除这个角色,只是从用户那里获得一个给定的角色。我做错了什么?

这是 SQL。注意最后一个 delete from roles 语句:

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

【问题讨论】:

    标签: ruby-on-rails-3.2 rolify


    【解决方案1】:

    基本问题是角色名称、资源类型和资源ID 的每个组合在roles 表中只存储一次。如果您删除此行,则会为所有人删除。

    然后解决方案是仅删除连接 UserRole 模型的 rolify 的 join table 中的行。为了便于访问,我将连接表作为模型来使用一些 rails 魔法来生成 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
    

    它只会删除你想要的。

    请注意,这不会删除带有角色的表格行,我会保留它以备将来使用。

    【讨论】:

    • 我把这个放在哪里?作为新的控制器?
    • 这不是一个新的控制器,而是一个用于连接表的 Active Recrod 模型,通常没有。
    【解决方案2】:

    我知道这个问题已经有两年多了,但我找到了更好、更“喜欢”的答案。
    你可以在用户模型中很容易地做到这一点:

    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 方法“remove”在适配器文件中:rolyfi: role_adapter.rb

    【讨论】:

      【解决方案3】:

      这就是我解决此问题的方法:

      models/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
      

      每次创建或更新用户时,删除用户的角色。

      【讨论】:

        【解决方案4】:

        转到config/initializers/rolify.rb

        取消注释该行

          config.remove_role_if_empty = false 
        

        所以文件现在看起来像这样:

        Rolify.configure do |config|
          
          # Configuration to remove roles from database once the last resource is removed. Default is: true
          config.remove_role_if_empty = false
        end
        
        

        默认情况下,remove_role_if_empty 设置为true,如果没有分配给任何其他用户,rolify 将删除角色。

        【讨论】:

          猜你喜欢
          • 2017-03-06
          • 2017-04-09
          • 1970-01-01
          • 2021-11-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-18
          • 1970-01-01
          相关资源
          最近更新 更多