Reputation: 10422
I'm using devise
with my rails 4 app to handle the authentication, and no problems there.
However, I want to make sure a logged in user can only view / edit (via the show
and update
actions) the items that his user owns (that are linked to his user_id
).
I think I could hack something to make this all work by checking the current_user.id
, but many users in Stackoverflow and other places say to use cancan
-- however it appears cancan
is dead and gone, and there's a replacement called cancancan
, which may be ok, but I don't know.
Is there a standard way to do this in Rails 4, or is the best route to still use a third party gem like cancancan
? Is there a better gem?
Upvotes: 1
Views: 871
Reputation: 1372
I'd recommend Action Access, it's much simpler and straightforward. It boils down to this:
class ArticlesController < ApplicationController
let :user, :all
let :guest, [:show, :index]
# ...
def edit
not_authorized! unless @article.user == current_user
# ...
end
# ...
end
First of this will automatically lock the controller, allowing only users to access every action, guests can only show or index articles. Then not_authorized!
will reject and redirect with an alert any user other than the owner of the article.
What's good about this is that it makes controllers to be self contained, everything related to the controller is within the controller. This also makes it very modular and avoids leaving forgotten trash anywhere else when you refactor.
It's completely independent of the authentication system (so no problem with Devise) but it bundles a set of handy model additions that allow to do things like:
<% if current_user.can? :edit, :article %>
<%= link_to 'Edit article', edit_article_path(@article) %>
<% end %>
Here :article
refers to ArticlesController
, so the link will only be displayed if the current user is authorized to access the edit
action in ArticlesController
. It supports namespaces too.
You can lock controllers by default, customize the redirection path and the alert message, etc. Checkout the documentation for more.
Upvotes: 0
Reputation: 13344
I don't think there's a standard, per se, but rather it's based on what you need. For Rails 4, cancancan brings a lot to the table and is built off of a gem that has been used regularly by the Rails community.
The only other alternatives I'm familiar with are protector and pundit - maybe check those out.
However, if cancancan and protector don't fit your needs, you could always roll your own authorization solution, but to me, why reinvent the wheel if cancancan will satisfy your needs.
Upvotes: 1
Reputation: 1977
I've been using Pundit instead of Cancan for the last few projects I've done. It is lightweight, flexible and easy to use. Here's the link: https://github.com/elabs/pundit
In regards to your question, you will create policies for each model. For each action you define a method. It's super simple and explained on the link I've attached. Here as an example you have update in your model (models/post.rb):
def update
@post = Post.find(params[:id])
authorize @post
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
Call authorize to define permissions.
In your policies/post.rb:
class PostPolicy < Struct.new(:user, :post)
def update?
user.admin? or not post.published?
end
end
That returns true or false. In your case if you want to check if the user is a owner you can place the following if statement:
if user.admin? || user.owner_of?(post)
You get the idea. You can also define scopes, etc.
Upvotes: 1