问题
I am really struggling to understand something that is fundamental to writing code in rails. I don't know what it is to ask a more fundamental question, but i seem to be having similar problems repeatedly.
I have managed to setup rolify in my Rails 5 app. I use rolify to assign roles to users.
Now, I'm trying to setup a function to remove roles from users after they are assigned.
In my user index, I have;
<% user.roles.each do |role| %>
<%= role.name.titleize %> <br>
<% end %>
That shows the roles that have been assigned.
Then, Im trying to add:
<%= link_to 'Destroy', role, method: :delete, data: { confirm: 'Are you sure?' } %>
My destroy method is defined in my assign_roles controller. It has:
def destroy
user = User.find(params[:users])
# role = AppRole.find(params[:roles])
assigned_role = user.roles
# user_roles = user.roles
# organisation = Organisation.first
# byebug
user.remove_role assigned_role.name, @current_user.organisation
flash[:notice] = "Successfully removed"
redirect_to action: :index
end
The routes are:
resources :users, shallow: true do
scope module: :users do
resources :assign_roles
end
There isn't an assign_role.rb model. I just use a controller and a view.
When I try to use the destroy role link in my user index, I get an error that says:
Couldn't find User with 'id'=
Can anyone see what I need to do to get the assign_roles#destroy action to work?
My create action in the assign_roles controller works. It has:
def create
user = User.find(params[:users])
role = AppRole.find(params[:roles])
# organisation = Organisation.first
@organisation = Organisation.find(@current_user.organisation)
# byebug
user.add_role role.display_name, organisation
flash[:notice] = "Successfully created"
redirect_to action: :index
end
Entire assign roles controller:
class Users::AssignRolesController < ApplicationController
before_action :authenticate_user!
def index
# if @current_user.is_admin?
@app_roles = AppRole.all
# else
# @app_roles = AppRole.where(category: relevant_category)
# end
# if @current_user.is_admin?
@users = User.all
# else
# @users = current_user.organisation.users.select { |u| u.id != current_user.organisation.owner_id }
# end
end
def create
user = User.find(params[:users])
role = AppRole.find(params[:roles])
# organisation = Organisation.first
@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.joins(:profiles).where('profiles.organisation_id = ?' @current_user.organisation.id)
# @users = User.all
@current_user.organisation.users
end
def update
end
def destroy
user = User.find(params[:users])
# role = AppRole.find(params[:roles])
assigned_role = user.roles
# user_roles = user.roles
# organisation = Organisation.first
# byebug
user.remove_role assigned_role.name, @current_user.organisation
flash[:notice] = "Successfully created"
redirect_to action: :index
end
end
I CAN DO WHAT I WANT TO DO FROM THE CONSOLE - I CANT FIGURE OUT HOW TO DO IT FROM THE CODE
In the console, I can write:
u.remove_role :fff, Organisation.first
That then successfully removes the role.
This is fine as a test, but in the code I'm trying to use current_user.organisation instead of Organisation.first. My objective is to allow a user to manage roles on its own organisation only.
In my assign roles controller, I have the destroy action copied above.
In my users index, I have an attempt to delete the assigned role from the user as:
<% user.roles.each do |role| %>
<table class="table table-bordered">
<tr>
<td><%= role.name.titleize %></td>
<td><%= link_to 'Remove role', role, method: :delete, data: { confirm: 'Are you sure?' } %></td>
The error says:
undefined method `role_path' for #<#
I wonder if I need to give it something else in the path so that it can find the assign roles#destroy action?
When I rake routes | grep assign, I can see:
DELETE /assign_roles/:id(.:format) users/assign_roles#destroy
I tried changing the path in my users index to:
<% 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), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
</table>
<% end %>
But then that gives this error:
Couldn't find User with 'id'=
I don't understand what this error means.
Another clue
Right, so I can see where the problem arises. I'm out of ideas for how to fix it.
In the console, I can successfully remove a user's role in the way I want to by doing this:
u.remove_role :sdfddd, Organisation.first
Organisation Load (2.0ms) SELECT "organisations".* FROM "organisations" ORDER BY "organisations"."id" ASC LIMIT $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 "roles"."name" = $2 AND "roles"."resource_type" = $3 AND "roles"."resource_id" = $4 [["user_id", 4], ["name", "sdfddd"], ["resource_type", "Organisation"], ["resource_id", 1]]
(0.1ms) BEGIN
SQL (0.4ms) DELETE FROM "users_roles" WHERE "users_roles"."user_id" = $1 AND "users_roles"."role_id" = 6 [["user_id", 4]]
(1.6ms) COMMIT
In the code, my current destroy action from the assign roles controller, which says:
def destroy
# user = User.find(params[:users])
user = User.find(params[:id])
# role = AppRole.find(params[:roles])
assigned_role = user.roles
# user_roles = user.roles
organisation = Organisation.first
# organisation = Organisation.find(current_user.organisation)
# byebug
user.remove_role assigned_role.name, organisation
flash[:notice] = "Successfully created"
redirect_to root_path
end
shows this process in the log:
User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 4], ["LIMIT", 1]]
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 4], ["LIMIT", 1]]
Organisation Load (0.7ms) SELECT "organisations".* FROM "organisations" ORDER BY "organisations"."id" ASC LIMIT $1 [["LIMIT", 1]]
Role Load (1.0ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND "roles"."name" = $2 AND "roles"."resource_type" = $3 AND "roles"."resource_id" = $4 [["user_id", 4], ["name", "Role"], ["resource_type", "Organisation"], ["resource_id", 1]]
The second parameter is a "Role", where maybe it should be the name of the role (i think). Role is a table name.
I'm not sure how to plug this in to make this work. Can anyone see how I can get code to process in the way I can do it in the console?
NEXT ATTEMPT
My new attempt at the destroy action in the assign_roles controller has:
def destroy
# user = User.find(params[:users])
user = User.find(params[:id])
# role = AppRole.find(params[:roles])
assigned_role = user.roles
# user_roles = user.roles
# organisation = Organisation.first
organisation = Organisation.find(current_user.organisation)
# byebug
user.remove_role assigned_role, organisation
flash[:notice] = "Successfully created"
redirect_to root_path
end
I think the problematic line is this one:
assigned_role = user.roles
It should be the specific role that I am trying to destroy (from the user's array of assigned roles).
The log shows:
[["user_id", 4], ["name", "#<Role::ActiveRecord_Associations_CollectionProxy:0x007f887ddb9c98>"], ["resource_type", "Organisation"], ["resource_id", 1]]
The role shouldn't be an array. It should be a specific role. So, my next guess is to try adding the role to the link in my users index, which is now:
<%= link_to 'Remove role', assign_role_path(user, role), method: :delete, data: { confirm: 'Are you sure?' } %>
Then, I need ideas for how I can rewrite the assigned_role line in my destroy action so that it knows which role I am trying to un-assign from the user.
I don't have any good ideas for how to do that.
# role = AppRole.find(params[:roles])
assigned_role = user.role
# user_roles = user.roles
Any ideas that might help push this thought forward?
回答1:
You are looking to destroy the role for just one User, right? So
params[:users]
shouldn't be plural, and :users isn't a valid key for params.
You're basically trying to
User.find(nil)
which fails with
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
You probably should use
User.find(params[:id])
来源:https://stackoverflow.com/questions/40229414/rails-5-rolify-removing-role-from-user