Pranjal Nanavaty
Pranjal Nanavaty

Reputation: 135

rails_admin filter data based on role

My rails_admin application is having two roles namely Teacher and Student such that every user belongs_to a role. I am using the gem cancancan to manage roles.

app/models

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 schema

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

Now, I want the project list to show all the data when role is Teacher but it should only show those projects where project.user_id == user.id when the role is Student.

That is, the final aim is to allow the role Student to see only his/her own projects thereby restricting the role Student to see all the projects where as the role Teacher should be able to see all the projects.

Upvotes: 0

Views: 1231

Answers (5)

Pranjal Nanavaty
Pranjal Nanavaty

Reputation: 135

To get data based on current user role I made the following changes to models/ability.rb.

Under the case when user role is Student

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

It will compare the user_id in projects table with the user.id so, in case of role Student it will only fetch the projects created by that student.

Upvotes: 2

Guillermo Siliceo Trueba
Guillermo Siliceo Trueba

Reputation: 4619

The answers provided asume the controllers can be changed and as the questioner points he does not have access to them.

Not sure if cancancan will handle the filtering of records based on view(read) permission on the index views of rails admin with a rule like this:

can :read, Project, user_id: user.id

But on the edit view i know you can configure a has many field to scope it based on the current user like this:

    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

Upvotes: 0

Puneet Agarwal
Puneet Agarwal

Reputation: 1

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

Upvotes: 0

current_user
current_user

Reputation: 1202

There is also another approach to achieve the functionality

create a new column called role in users table

     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

And in the user model

     class User < ApplicationRecord

      enum role: [:student, :teacher, ]
      after_initialize :set_default_role, :if => :new_record?

     def set_default_role
     self.role ||= :student
     end

     end

This creates a default role as student when a new user signs up.you can change the role of the user to teacher by simply doing

go to rails console in the terminal using rails c

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

Now the role of the user is teacher.

  class ProjectsController < ApplicationController

  if current_user.teacher?
    @projects = Project.all
  else
    @project = current_user.projects
  end

Upvotes: 0

darkknight
darkknight

Reputation: 1

Your controller will have an action to list projects. Just use a before_action filter to load projects based on role. Assuming, you are setting current_user in application's base controller and have association b/w student and 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

You can also add association between projects and teacher. And user teacher.projects if you need.

Upvotes: 0

Related Questions