What do we want our roles to be able to do?
Let's start with destroy, which only an Admin should be able to do.
A user should only be able to delete an article if:
We are going to pretend that we're doing test driven development here. You write the code how you want it to work, and then you write the code that makes it work. This can greatly help simplify your code! We are going to use methods, like
.admin?
before we've defined them.
def destroy
@article = Article.find(params[:id])
if @article.user == current_user || current_user.admin?
@article.destroy
redirect_to articles_path
else
redirect_to :root, alert: "You do not have permission to do that."
end
end
What are the rules for changing an article?
A user should only be able to update an article if:
def update
@article = Article.find(params[:id])
if @article.user == current_user || current_user.editor? || current_user.admin?
if (current_user.editor? || current_user.admin?) || @article.user == current_user
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
else
redirect_to :root, alert: "You do not have permission to do that."
end
end
Now we only want to show the edit link if the user is an editor or an admin
<% if article.user == current_user || current_user.admin? || current_user.editor? %>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<% end %>
But that sucks... That's a lot of code, and we would repeat that all over the place!
What about a HELPER?
module ArticlesHelper
def can_edit_article?(article)
article.user == current_user || current_user.admin? || current_user.editor?
end
end
Now let's change our view
<% if can_edit_article?(article) %>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<% end %>
Much better!
Our controller code is still pretty WET though. How do we DRY it out?
We could include the helpers into our controller, which is ok
class ArticlesController < ApplicationController
include ArticlesHelper
or we can use pundit to replace both controllers and views!
Pundit is pretty easy and can really DRY up your views and controllers. If you feel sufficiently advanced, you can try it out for your final project. Otherwise it might be best to stick with basic authorization!
Pundit: https://github.com/elabs/pundit
We have these extra methods on our model, editor?
, writer?
etc.
rails generate migration AddRoleToUser role:integer
, default: 0
to the end of the add_column
.rake db:migrate
Right now our roles are all just numbers, 0, 1, 2. That's easy to forget and hard to use. We will use an enum
to add all of those cool question mark methods to our models.
user.rb
enum role: [:writer, :editor, :admin]
user.writer?
and user.editor?
"writer"
In this way we can create roles for our users that we can use as if they are English! We can even output them in the views. <p><%= user.role %></p>
would output <p>writer</p>