Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5 - Rolify - trying to remove an instance of a role from a user

I am trying to learn how to use rolify with my Rails 5 app.

I've previously asked lots of questions about Rolify, most recently here but I've not been able to find help.

Im struggling to try to figure out how to remove an assigned role from a user.

The tables in my schema have tables for app_roles (which is my CRUD for making the roles that can separately be assigned to users), users, roles and user_roles - as:

create_table "app_roles", force: :cascade do |t|
    t.string   "title"
    t.string   "display_name"
    t.integer  "category"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
  end

  create_table "users", force: :cascade do |t|
    t.string   "first_name"
    t.string   "last_name"
    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.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.string   "confirmation_token"
    t.datetime "confirmed_at"
    t.datetime "confirmation_sent_at"
    t.string   "unconfirmed_email"
    t.integer  "failed_attempts",        default: 0,  null: false
    t.string   "unlock_token"
    t.datetime "locked_at"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.integer  "organisation_id"
    t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
    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
    t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true, using: :btree
  end

  create_table "users_roles", id: false, force: :cascade do |t|
    t.integer "user_id"
    t.integer "role_id"
    t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
  end

create_table "roles", force: :cascade do |t|
    t.string   "name"
    t.string   "resource_type"
    t.integer  "resource_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
    t.index ["name"], name: "index_roles_on_name", using: :btree
  end

The associations are:

User

rolify strict: true # strict means you get true only on a role that you manually add
  attr_accessor :current_role

Role

has_and_belongs_to_many :users, :join_table => :users_roles

  belongs_to :resource,
             :polymorphic => true,
             :optional => true

App Roles (has no associations - It's the CRUD I use to make new roles via a form)

My user model has:

class User < ApplicationRecord
  rolify strict: true # strict means you get true only on a role that you manually add
  attr_accessor :current_role

I couldn't figure out how to assign roles just using rolify the way its shown in the wiki. That's why I made a separate resource. It's called assign roles. I have an assign_roles_controller.rb which has:

class Users::AssignRolesController < ApplicationController

  before_action :authenticate_user!

  def index
      @app_roles = AppRole.all
  end


  def create
    user = User.find(params[:users])
    role = AppRole.find(params[:roles])
    organisation = Organisation.find(current_user.organisation)
     # byebug

    user.add_role role.display_name, organisation

    flash[:notice] = "Successfully created"
    redirect_to action: :index
  end

  def show
    @users = User.all
  end

  def update
  end

  def destroy

    # user = User.find(params[:users])
    # user = User.find(params[:id])
    user = User.find_by_id(params[:id])
    # User.find(params[:id])
    # role = AppRole.find(params[:roles])
    role = params[:user][:roles]
    # assigned_role = user.roles
    # user_roles = user.roles
    # organisation = Organisation.first
    organisation = Organisation.find(current_user.organisation)

    # byebug

    user.remove_role role.display_name, organisation

    flash[:notice] = "Successfully created"
    redirect_to root_path
  end

end

The routes are nested, so I have:

resources :users, shallow: true do
    scope module: :users do
      resources :assign_roles

In my users index, I'm trying to show a list of users, with each of their roles and a remove role link. In the users/index.html.erb, I have:

<% user.roles.each do |role| %>
              <table class="table table-bordered">
              <tr>
                <td><%= role.name.titleize %></td>
                <td><%= link_to 'Remove role', assign_role_path(user.roles),  method: :delete, data: { confirm: 'Are you sure?' } %></td>
              </tr>
              </table>
             <% end %>

In the console, I can do:

Organisation.find_roles(nil, User.find_by(organisation_id:1))
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."organisation_id" = $1 LIMIT $2  [["organisation_id", 1], ["LIMIT", 1]]
  Role Load (0.7ms)  SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (resource_type IN ('Organisation'))  [["user_id", 43]]
 => #<ActiveRecord::AssociationRelation [#<Role id: 3, name: "asdf", resource_type: "Organisation", resource_id: 1, created_at: "2016-10-24 23:00:40", updated_at: "2016-10-24 23:00:40">, #<Role id: 4, name: "ffff", resource_type: "Organisation", resource_id: 1, created_at: "2016-11-09 00:26:56", updated_at: "2016-11-09 00:26:56">]> 

The user has 2 roles.

When I try to remove one of them, I get an error that says:

undefined method `[]' for nil:NilClass

That error complains about this formulation (which is a copy from someone's suggestion on another SO post) in the destroy action of my assign roles controller:

role = params[:user][:roles]

When I try the destroy action as:

def destroy
    user = User.find_by_id(params[:id])
    assigned_role = user.roles
    organisation = Organisation.find(current_user.organisation)

    # byebug

    user.remove_role assigned_role.display_name, organisation

    flash[:notice] = "Successfully created"
    redirect_to root_path
  end

I then get an error which says:

undefined method `roles' for nil:NilClass

I think that error may have something to do with me trying to remove one role from the user but I'm using plural to find them all. I'm not sure how to find the specific one role that I'm referencing in the uses index.

Can anyone help me figure this out?

like image 751
Mel Avatar asked Jan 24 '26 11:01

Mel


2 Answers

Please refer this once.

 def destroy
    user = User.find_by_id(params[:id])
    assigned_role = user.role_name
    organisation = Organisation.find(current_user.organisation)

    # byebug

    user.remove_role assigned_role, organisation

    flash[:notice] = "Successfully created"
    redirect_to root_path
  end
like image 157
Atul Shukla Avatar answered Jan 26 '26 23:01

Atul Shukla


I had a session on codementor and finally got to an answer.

The answer is:

def destroy
#/assign_roles/9?user_id=27
    user = User.find_by_id(params[:user_id])
    assigned_role = Role.find(params[:id])
    organisation = Organisation.find(current_user.organisation)

    user.remove_role assigned_role.name.to_sym, current_user.organisation #user.organisation

    flash[:notice] = "role deleted"
    redirect_to root_path
  end

And in the view:

        <td><%= link_to 'Remove role', assign_role_path(role, user_id: user),  method: :delete, data: { confirm: 'Are you sure?' } %></td>

The specific issue is that the role name needs to be converted to a string before it can be removed and the user find method is searching in the closest resource (which means it is looking for an id in the role model, not the user model. That means that id will fail to return the user id. I don't understand the search structure of this part of rails - so I have to take that as given (without understanding it), but very happy, that after years of trying to solve this problem, I can move on.

like image 27
Mel Avatar answered Jan 27 '26 01:01

Mel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!