问题
I am trying to make an app with Rails 4.
I am looking at role management and want to use Rolify because it supports instance level role assignment.
For others looking at the same problem, there are 2 really good answers below (I can only tick one but I used both). Check out lorefnon & Cyb3rDud3 answers below). I'm still figuring it out, but have made a migration with an array (as lorefnon shows) and the controller/routes functions (as Cyb3rDud3 shows).
What is completely baffling me is that all the documents for the Rolify gem use the console to define roles.
How do I define roles in my code?
Others on this board have asked questions which allude to them defining roles in their db:seeds file. I don't want to do that because I want to control who uses my seeds file more tightly than who can create roles.
Where do you do it?
All the examples show it being done from the console. I want to define a list of roles and then I want to give roles permissions (I want to use pundit for this part).
I have a user model. The other gem I looked at was role model. It asks you to create an array of roles in the user model. It it just so obvious that you're supposed to do that in Rolify- that none of the documents give you this step?
Where do you define the roles?
回答1:
What is completely baffling me is that all the documents for the Rolify gem use the console to define roles.
Rolify documentation does not use the console to define roles - it demonstrates how roles can be added in pure ruby. This is amazingly powerful because you can define roles whereever you can run ruby. You are not restricted to a static list of roles defined in some configuration file or in some database table.
The first question you need to ask is when do the roles get created ?
The most common use cases fall into two groups:
1. Roles are static.
Roles are created once by the application developer, support staff or company executives during application installation/deployment and during the lifetime of the running application these pre-created roles are assigned to different users.
The most common use cases of such roles includes modelling designations of a people in a company (developer, manager, support etc.), or modelling priorly known responsibilities (editor, administrator, viewer etc.)
If your roles do fall into such use cases, next thing you have to decide - whose responsibility is it to create and modify the roles. There are typically two possibilities:
1.1. Application developer himself is the person who has to add/remove/modify roles. In such cases it is best to rely on seed data or Rails migrations.
Advantage of migrations is that you can rollback the data easily if need be. This migration is additional to migration generated by rolify generators which create the schema of roles related tables for you (refer to the diagram below).
Such a migration might look like:
db/migrate/20151204083556_create_application_roles.rb
class CreateApplicationRoles < ActiveRecord::Migration
def up
['admin', 'support', 'editor'].each do |role_name|
Role.create! name: role_name
end
end
def down
Role.where(name: ['admin', 'support', 'editor']).destroy_all
end
end
Some people rightly consider it an antipattern to have schema changes and data changes both managed by migrations. data-migrate is a gem that allows you to separate the data centric migrations from your schema migrations.
In this case and all the other cases below actual assignment of roles will happen based on user actions or application events through add_role
or remove_role
methods provided by rolify.This will happen during the course of the lifecycle of running application and not during application installation.
1.2 The task of adding/removing/modifying roles is done by a support team or technical executives. In such cases it would be required to provide an administrative interface for managing roles.
In this case you will have a rails controller to manage the roles. The create action will be used for creating role, show action will be there to present the role etc. These actions will have accompanying views that will provide a graphical user interface to end user to manage the roles.
2. Roles are dynamic
This category covers use cases where roles are treated more like categories or tags and can be created/modified/deleted by end users. For example a librarian can assign some role/category to a particular genre of books.
This case is similar to 1.2 because you have to handle creating/deleting/updating roles through rails controllers.
Next part is how the information is structured in your tables.
Rolify expects a specific schema (customizable to certain extent) but the expected schema is flexible enough to handle all the above use cases.
回答2:
I've literally just gone through the same process, and like @user2860931 all I could find was some examples on how to assign roles from the console. What I required is a programmatically flexible way on how a user with the admin role or user with say the pmo role can assign those roles to others.
With a little bit of experimenting, this is how I resolved it for me. In this example I am using Devise for authentication, and Rolify for the roles.
I assume you have Devise already installed and working, therefore that you have an existing User model. Install Rolify as per the instruction on the gem page. I used the proposed name Role for the roles model. So do everything as stated here: https://github.com/RolifyCommunity/rolify. Install the GEM, generate using rolify the Role User. And migrate the database migration.
This will effectively leave you with a new table Roles and a has_and_belongs_to_many relationship with the Users table.
As for my purpose I do not require the usual Create Read (show) Update Delete (CRUD) interface for the roles, I just created a few via the seeds.rb like this.
#Seeding the Role table
#
p "Removing existing #{Role.all.count} roles"
Role.destroy_all
p "Creating 7 roles"
[:user, :admin, :portfolio_manager, :programme_manager, :project_manager, :coordinator, :pmo].each do |role|
Role.create( name: role )
end
p "Should have created 7 Roles, roles created: #{Role.all.count}"
I've left my additional commentary in as I do with the development stuff so I can see at a glance it worked fine. So when you run
rake db:seed
You'll have some roles setup. Alternatively you can create a roles controller and views in the usual way to allow say users with admin role add new roles.
Now the fun bit can begin. So far Devise has done everything regarding your users, or perhaps you've done your own controller anyway but you need to create your own users controller and views. As I want just a list of tick boxes for the roles against each user I've done it as follows. Here is my
users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update]
def index
@users = User.all
end
def show
end
def edit
end
def update
respond_to do |format|
if @user.update(user_params)
# TODO: Move hardcode flash message into language file
format.html { redirect_to @user, notice: 'User was successfully updated.'}
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
private
def set_user
@user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:username, :email, {role_ids: []})
end
end
Now you've got to define the routes for these such that they don't clash with the Devise routes. I've kept it simple for now and resourced all the usual routes for to harden your application you may want to change that and only allow routes for those that you actually have.
routes.rb
Rails.appliction.routes.draw do
devise_for :users
root 'pages#home'
resources :users #must be after devise
end
When you now do a rake routes you'll get the usual paths for your application to make the controller work. Like this and in that order:
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
user_unlock POST /users/unlock(.:format) devise/unlocks#create
new_user_unlock GET /users/unlock/new(.:format) devise/unlocks#new
GET /users/unlock(.:format) devise/unlocks#show
root GET / pages#home
about GET /about(.:format) pages#about
contact GET /contact(.:format) pages#about
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
All that is left to do now is build the user interface, the most important part to me, and if I understood correctly to you as well. In order to build this quickly, my example is not nicely presented yet with full css magic but I'm sure you can do that to your own taste.
So to show existing users and pick them of a list, create the index.html.erb in your /app/views/users folder. Create a simple show.html.erb and an edit in which you can assign and remove the existing roles. Like this.
index.html.erb
<!-- TODO: Tidy up this file and make it look good -->
<!-- TODO: Remove hard coded text to a locale file -->
<% @users.each do |user| %>
<p>
<%= link_to "#{user.username}<#{user.email}>", user %>
<%= link_to "edit", edit_user_path(user) %>
</p>
<% end %>
show.html.erb
<!-- TODO: Tidy up this file and make it look good -->
<!-- TODO: Remove hard coded text to a locale file -->
<p>
Username: <%= @user.username %>
</p>
<p>
Email address: <%= @user.email %>
</p>
<%= link_to "Back", users_path %>
edit.html.erb
<!-- TODO: Tidy up this file and make it look good -->
<!-- TODO: Remove hard coded text to a locale file -->
<p>
Username: <%= @user.username %>
</p>
<p>
Email address: <%= @user.email %>
</p>
<%= form_for @user do |f| %>
<% Role.all.each do |role| %>
<%= check_box_tag "user[role_ids][]", role.id, @user.role_ids.include?(role.id) %>
<%= role.name %></br>
<% end %>
<%= f.submit %>
<% end %>
<%= link_to "Back", users_path %>
And there you have it, a simple user interface which lists all available roles from the database and provides tick boxes against a user record to enable or disable such a role. Like this:
Example of user record and role pick list
It was a little head scratcher for me as well, but hopefully this will put your on your way to increase the logic and user experience.
回答3:
After reading the documentation and examples in their project pages I decided not to use a gem for managing roles in my page cause I considered it would take me lot of time to configure and to use. So instead I did the following, (I believe you used devise for your user model, even though it's not mandatory) :
If you want to have certain roles defined and "static" non-modificable but assignable from your page see below, if not jump to the next bold line
- Add a field called
role: integer
to yourUser
model with a migration. (we use integer cause this value will be associated with one entry in the enum we define in the next step) In your file
user.rb
(the model), add anenum
like below:class User < ActiveRecord::Base devise :registerable, #... enum role: [:admin, :normal, :premium, :moreRolesHere ] after_initialize :set_default_role, :if => :new_record? def set_default_role self.role ||= :normal end end
Then in any controller or view or
def
you just have to get the current user or any user you want to assign a role and do as simple as the line below:#let's suppose we want to make premium the current user current_user.premium! #or someone else to be admin user = User.first user.admin!
Then you can make your own validations in any page or controller you are working on, just by asking the role of the user:
#see if the current user is admin if current_user.role == "admin" #do some admin stuff end
If you want to add, modify and delete roles in your page and also assign them in there
First of all, be careful when you assign roles directly from your page. The problem here is that everyone will be able to assign himself his own role selected in a field. But if this is what you need, do as below:
- Create a model called
Role
, with a fieldrole: string
- Create the controller associated to that model,
roles_controller.rb
- Create the views you need in order to display the actions related to the management of the roles (create, edit, delete) be careful that this pages have to be only available to signed in users. The selection or addition of a role to a user you will manage inside your users controller or any other controller you want.
In any other view you want to ask for the role of a user you will need to access the roles table and retrieve the one(s) corresponding to the user. The users table will need a column
role_ids: text
(it's text cause you need multiple roles to be saved there, all roles wrapped in an array), which will represent his roles. In youruser.rb
model you could have aget_roles
and otherdef
s methods to have cleaner code in controllers and views:class User < ActiveRecord::Base devise :registerable, #... serialize :role_ids #will return you an array of roles-(strings) of the user def get_roles roles = [] role_ids.each do |role_id| roles << Role.find(role_id).role end return roles end #ask if this user has some role-(string) def has_role(role) roles = get_roles return roles.include?(role) end end
Lastly, of course you will need to implement the controller for roles, the create, update and destroy and all the
def
s associated to their views.
You could take a look at how to save arrays in database, serialize
This approach make no use of any gems related to role management or authorisation like those in the market: pundit, cancan, rolify. Leave you some links if you are skeptical with my approach and want to get your hands dirty.
来源:https://stackoverflow.com/questions/33950172/defining-roles-with-rolify