【问题标题】:rails_admin filter data based on rolerails_admin 根据角色过滤数据
【发布时间】:2017-10-11 07:07:25
【问题描述】:

我的rails_admin 应用程序有两个角色,即TeacherStudent,这样每个用户belongs_to 都有一个角色。我正在使用gem cancancan 来管理角色。

应用/模型

class Role < ApplicationRecord
    has_many :users
end

class User < ApplicationRecord
    belongs_to :role
    has_many :projects
end

class Project < ApplicationRecord
    belongs_to :user
end

Project 架构

create_table "projects", force: :cascade do |t|
    t.string   "name"
    t.string   "description"
    t.integer  "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_projects_on_user_id", using: :btree
  end

现在,我希望项目列表在 roleTeacher 时显示所有数据,但它应该仅在 roleStudent 时显示 project.user_id == user.id 的那些项目。

也就是说,最终的目的是让roleStudent只能看到他/她自己的项目,从而限制roleStudent看到所有roleTeacher的项目应该可以看到所有的项目。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 cancan rails-admin cancancan


    【解决方案1】:

    为了根据当前user 角色获取数据,我对models/ability.rb 进行了以下更改。

    用户roleStudent的情况下

    can :read, Project, ["user_id = ?", user.id] do |project|
        project.present?
    end
    

    它将projects 表中的user_iduser.id 进行比较,因此,在role Student 的情况下,它将仅获取该学生创建的项目。

    【讨论】:

      【解决方案2】:

      您的控制器将具有列出项目的操作。 只需使用before_action 过滤器即可根据角色加载项目。 假设您在应用程序的基本控制器中设置 current_user 并关联 b/w student 和 project - student has_many projects。

      ProjectController
        before_action :load_projects, only: [:index]
      
        def index
          @projects
        end
      
        private
        def load_projects
          if current_user.role == "Teacher"
            @projects = Project.all
          elsif current_user.role == "Student"
            @projects = current_user.projects
          end
        end
      end
      

      您还可以在项目和教师之间添加关联。如果需要,用户 teacher.projects

      【讨论】:

      • 其实是一个rails_admin的应用,我们只需要写模型;控制器和视图功能由gem rails_admin 完成/生成。因此,为rails_admin 应用程序定制控制器是不可行的。
      【解决方案3】:

      还有另一种实现功能的方法

      在用户表中创建一个名为角色的新列

           create_table "users", force: :cascade do |t|
              t.string   "email",                  default: "",    null: false
              t.string   "encrypted_password",     default: "",    null: false
              t.string   "reset_password_token"
              t.datetime "reset_password_sent_at"
              t.datetime "remember_created_at"
              t.integer  "sign_in_count",          default: 0,     null: false
              t.datetime "current_sign_in_at"
              t.datetime "last_sign_in_at"
              t.string   "current_sign_in_ip"
              t.string   "last_sign_in_ip"
              t.datetime "created_at",                             null: false
              t.datetime "updated_at",                             null: false
              t.integer  "role"
              t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
              t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
            end
      

      在用户模型中

           class User < ApplicationRecord
      
            enum role: [:student, :teacher, ]
            after_initialize :set_default_role, :if => :new_record?
      
           def set_default_role
           self.role ||= :student
           end
      
           end
      

      当新用户注册时,这会创建一个默认角色为学生。您只需执行以下操作即可将用户角色更改为教师

      在终端中使用 rails 控制台 rails c

        u = User.find_by_id(1) 
        # you can change value '1' depending upon your user_id
        u.role = "teacher"
        u.save
      

      现在用户的角色是老师。

        class ProjectsController < ApplicationController
      
        if current_user.teacher?
          @projects = Project.all
        else
          @project = current_user.projects
        end
      

      【讨论】:

      • 由于是rails_admin应用,控制器和视图都是gem rails_admin生成的,所以不能修改控制器。因此,我需要一种方法来过滤模型本身的数据。
      【解决方案4】:
      class User < ApplicationRecord
          belongs_to :role
          has_many :projects
      
          def projects
              if self.role.to_s == "student"
                  super projects
              else
                  Project.all
              end
          end
      end
      

      【讨论】:

      • 欢迎来到 Stack Overflow。请查看How do I write a good answer。不鼓励仅使用代码的答案,因为它们没有解释如何解决问题中的问题。您应该更新您的答案以解释它的作用以及它将如何帮助 OP。
      【解决方案5】:

      提供的答案假设控制器可以更改,并且作为提问者指出他无权访问它们。

      不确定cancancan是否会根据rails admin的索引视图的视图(读取)权限处理记录过滤,规则如下:

      can :read, Project, user_id: user.id
      

      但在编辑视图中,我知道您可以配置一个有很多字段来根据当前用户对其范围进行调整,如下所示:

          edit do
            field :projects do
              associated_collection_scope do
                current_user = bindings[:controller].current_user
                proc { |scope| scope.where(user: current_user) }
              end
            end
          end
      

      【讨论】:

      • 谢谢伙计,我根据 cancan gem 处理了您的建议。稍加修改,我就能得到想要的结果。我将发布我的解决方案作为答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-27
      • 1970-01-01
      • 2019-03-17
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 2012-04-16
      相关资源
      最近更新 更多