Ruby on Rails (3) hiding parts of the view - ruby-on-rails

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 %>

Related

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.

Devise: logic using `admin_signed_in?` when Admin & User logged in on separate tabs in same browser

In my Rails 3.2 app there are two Devise models: User and Admin. I have a comment partial form that both can use to make comments on a Post. However, I have included conditional logic with the *_signed_in? helper provided by Devise so that a checkbox appears for admins that allows them to make their comment visible only to other admins. Form checkbox code:
- if admin_signed_in?
.pull-right
= label_tag :internal, "Private"
= f.check_box :internal
It's not a huge issue because it should never occur in production, but in development and staging I've noticed that if someone (tester, etc) is logged in as both an Admin and a User in different tabs on the same browser, the logic of my form doesn't work because (I guess?) those two tabs are using the same cookie/session info/whatever. The checkbox shows up on the User's form because the Admin is signed in on the other tab. It works fine if two different browsers are being used.
Is there a way to avoid this?
You may need to find or create a variable that can be used to determine if you're in the admin part of the site. A cheesy way would be to put a before filter in your admin controller(s) that sets an instance variable (#admin_site = true for example) then update your partial thus:
- if admin_signed_in? && #admin_site
.pull-right
= label_tag :internal, "Private"
= f.check_box :internal
However it's considered bad practice by some (Sandi Metz for example) to proliferate the instance variables sent to the view. Also, it's a good idea to pass parameters in to partials explicitly as locals rather than relying on instance variables. (This helps readability and makes it easier to share them in general).
The facade pattern can help here.
http://robots.thoughtbot.com/sandi-metz-rules-for-developers
Edit:
Since using the facade I tend to spurn helpers in general, but you could probably do something like this:
#app/helpers/application_helper.rb
module ApplicationHelper
def show_internal?
request[:controller].in? ['admin']
end
...
Assuming your admin actions are all in a controller called 'admin_controller'.
You can add more admin controllers if you have many, by adding to the array:
request[:controller].in? ['user_admin', 'product_admin']

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.

Rails + Devise: How to restrict a user from editing records that do not belong to him

I'm using Rails, Devise and Mongoid.
A user can only have one project (has_one :profile) but all users (and non authenticated users) can see a list of projects (I have this working). When a user is logged in they see "edit and delete" buttons next to the projects (via wrapping those buttons in <% if user_signed_in? %>). However, a signed in user sees these buttons next to all project and can edit or delete them all.
How do I restrict a logged on user to only be able to edit only his project?
As a bonus, is it possible to show specific content or html around the project that belongs to the signed in user (such as text that says "this is your project" or an additional class around the project's html)?
CanCan is great when you have multiple users being able to modify the same resource, and you need to keep track of who has which permissions. But if it's strictly the case that only the user who owns the project can modify it, CanCan is probably overkill.
Hide the links in the view as suggested by iouri, and then in your controller do something like:
def edit
if current_user != #project.user
# Redirect them to an error page
else
# Render the view
end
end
Better yet, create a method like:
def user_owns_project?
#project.user == current_user
end
Then set up a before filter for edit, update and destroy to redirect to the error page if the user doesn't own the project.
EDIT: Your before filter will also ned to find the project and set #project. CanCan takes care of this for you too with load_and_authorize_resource, but I'd still avoid using it unless you need, or expect to need, fine-grained permissions control.
Devise is to control "authentication", this should not to be your responsibility.
You want to control "authorizations", for that CanCan is better.

Rails user authorization

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?

Resources