Rails user authorization - ruby-on-rails

I am currently building a Rails app, and trying to figure out the best way to authenticate that a user owns whatever data object they are trying to edit.
I already have an authentication system in place (restful-authentication), and I'm using a simple before_filter to make sure a user is logged in before they can reach certain areas of the website.
However, I'm not sure the best way to handle a user trying to edit a specific piece of data - for example lets say users on my site can own Books, and they can edit the properties of the book (title, author, pages, etc), but they should only be able to do this for Books that -they- own.
In my 'edit' method on the books controller I would have a find that only retrieved books owned by the current_user. However, if another user knew the id of the book, they could type in http://website.com/book/7/edit , and the controller would verify that they are logged in, then show the edit page for that book (seems to bypass the controller).
What is the best way to handle this? Is it more of a Rails convention routing issue that I don't understand (being able to go straight to the edit page), or should I be adding in a before_find, before_save, before_update, after_find etc callbacks to my model?

check out the following gems:
cancan
devise
authlogic
and don't miss Ryan's great railscasts on the above

this will give access to anyone who changes the value in the address bar
#book = Book.find(params[:id])
but if you go through the association of the logged on user rails (ActiveRecord) will automatically update the sql query
#book = current_user.books.find(params[:id])
of course this assumes that your books table has a user_id column

You may need an authorization plugin. I had some experience use this plugin a while back. This article also has an overview:

You might also take a look at Declarative Authorization

Hey I have recently done this myself. The easiest way to do this is to have the edit feature display on the page but incase it in a method such as the following:
<%if current_user %>
<% if current_user.id == wishlist.user_id %>
<div id="text3"><%= link_to 'Edit', edit_wishlist_path(#wishlist) %></div><br />
<%end%>
<%end%>
Is this what you were hoping for?

Related

How to make an object appear different to the poster in Ruby on Rails?

I'm working on a project that will allow people to create groups then send a task to all of the people who are apart of that group. When the person who matches the same user_id as the value attached to the task, I would like it for the task to appear different (different text on it and some other stuff) and when you click it, it shows analytics for that task. I just need to know what it takes for me to pull of altered versions of an object for the person who posted it. Thanks for any help. I may be too vague here, I'm still very new to Rails.
If a task belongs to a user, and you have access to current_user (if you're using devise it's built in, w/ bcrypt you'll have to write yourself), an easy way to do this in the views would be to say something like:
<% if task.user_id == current_user.id %>
<-- stuff you want to show the assigned user -->
<% else %>
<-- stuff you want to show everyone else -->
<% end %>
Assuming you're using erb. But you get the gist.

Rails radar/forem forum engine - controlling access to certain forums or topics

I'm using forem as forum engine and have it attached to my User model.
As part of my User model, I have "experts" and "novices" as the two different types of users.
If I only want to show the "expert" forum to "expert" users, what is the best way to control this access within forem?
You could try to modify the view under app/views/forem/forums/_forum.html.erb, enclosing all with this:
<% if forem_user.expert? %>
...
<% end %>
Note: if you don't have the forem views, you have to generate them with rails g forem:views.
Cheers!
EDIT:
The last version of Forem allows to redefine methods for permissions in your User model.
https://github.com/radar/forem/wiki/Authorization-System
So, in your case, you'd define the method can_read_forem_forum?(forum) and return true if the user is expert.

Newbie with Rails devise and view of the user

I'm looking into RoR some way to: login into the system with DEVISE, (it's working), but i'm needing something than keeps always the view of this logged user, and avoid than this user looks another views.
http://xx.xx.xx.xx:3000/user/1
And this user cannot look the content of:
http://xx.xx.xx.xx:3000/user/2.
Please, sorry if this is a silly question, but, i was looking 2 days and i don't know how i can name this feature.
Thanks!
There are gems available for this Authorization. I prefer can can which is one of the best Authorization gems available
Here is the gem=> https://github.com/ryanb/cancan
And here is the rails cast tutorial using it=> http://railscasts.com/episodes/192-authorization-with-cancan
EDIT: If you want to manually implement this then you just need to make a method with following logic
def check_authorization
# Assuming user ID is coming in params[:id]
if current_user.id == params[:id]
return
else
# render or redirect to some page with access denied message
end
end
And call this method just before any action in which you want to check for authorization.

Ruby on Rails (3) hiding parts of the view

I am working on a Ruby on Rails 3 web application.
I have a table named User with a coulmn named role. I am looking for the best way to hide parts of the view from users that have the "wrong" role for those parts of the view.
For example I want all users to be able to see the users index page, but i want only users with a role - admin to be able to edit other users.
So first I block the edit action using filter_by, but what I also want is make the edit button not to appear.
The current user is saved in the session, so checking the user role is very simple.
What I am asking, is there an easy way to do so besides the obvious if statement before each button I want to hide. I would think that rails would have an easy way to do this type of thing, I couldn't find one.
You may want to use Devise and CanCan.
https://github.com/plataformatec/devise
https://github.com/ryanb/cancan
Here is a RailCast tutorial
http://railscasts.com/episodes/192-authorization-with-cancan
if you wanted to clean it up a tiny bit you could write yourself an application helper:
def if_admin(user)
if(user.is_admin? && block_given?)
yield
return
end
end
then in your view you could write:
<% if_admin(#user) do %>
<some admin only html />
<% end %>

Braintree "shopping cart"-like implementation in rails app / finding previous params[:id]?

I'm trying to integrate Braintree into my rails app which already has a deposits controller, model, and view. Right now basically you can specify an amount but I have its status set to "Pending". I would like it so that the user can make such a deposit but then pay for it at any time using Braintree (ala shopping cart). Would I have to create another controller and/or model to do this? (For example all the Braintree examples I've seen want the payment immediately).
Specifically, I've been trying to just work with the 'deposits' I already have. I put the form for the user's name, credit card info, etc. on the deposits "show" page and a confirm button. This seems to work fine if all fields satisfy validation, however it doesn't when there is an error and renders the show page again.
In DepositsController.rb:
def confirm
#deposit = Deposit.find(params[:id])
#result = Braintree::TransparentRedirect.confirm(request.query_string)
if #result.success?
render :action => "confirm"
else
render :action => "show"
end
end
The problem is that :id now is the Braintree transaction ID, rather than the deposits id (primary key). So of course Deposit.find(params[:id]) can't be found.
What is the best way to implement this? Should I store the previous id somehow or get it another way? Should I be using another controller? Thanks!
Short answer is you should be using a Cart model, connected to this Deposit model from what i can gather here. Based on other questions, however, that feeling could change.
So, solely based on what you wrote above:
If we follow a RESTful approach, you should be creating a Deposit#new for all new deposits.
In your Deposit#create, you would then put all of your logic into the deposit.rb model file. this logic includes, going to Braintree and such.
You say you are working with the deposits you already have, in that case, they should be handled in the Deposit#edit method.
Further questions I would ask of you in this regard, are you using ActiveMerchant? If not, why not?

Resources