Authorization with Devise and multiple levels - devise

I need some help with the authorization. So far I was trying to solve it with the internal rails authorization combined with devise.
I have a user who is posting a request. If this request is private only a group of "reader" can see and answer the request. (This is number one)
Then the user give a rating to the answer of the reader. This should be accesible only for the user which received the answer and the "reader" who gave an answer.
So far I was using the following to limit access to the hidden requests:
before_filter :require_reader!, only: [:open_requests]
But if the request is not hidden, than still only the reader should be able to answer the request (but all can see it). Here I do not know how to manage this. Any Ideas?
To continue... I could not manage to solve the second problem (that the rating is seen only be the one who was placing the request and the reader).
Any ideas here?
Is cancancan maybe an option?
Best
witali

What you're doing does not quite follow the 'admin' pattern that's commonly setup with tools like Railsbricks. The 'admin' permissions pattern is typically a whole set of actions/views that are available only to admins, so often the entire Controller, or family of controllers, have the :require_admin! filter applied before every single action and view. Very simple permissions logic, and it depends only on the user and view.
Instead, what you've got is views with permissions that depend on your object's state as well as the user's status and the view. So you're going to have to write your own filter to use instead of using 'require_reader!'.
For example, you might have a RequestsController, and you could add to it:
before_action :must_be_able_to_view_request, except: [:index, :new, :create]
Then define that filter in the controller:
private
def must_be_able_to_view_request
if !current_user.is_reader? && !#request.ispublic
head :forbidden
end
end
If you need to use the same filter in other Controllers, then you can define it in your ApplicationController.

Related

Rails 3 - Model related to current user in controller

We assume an authentication system is setup and we have access to a variable current_user, e.g.: using the Devise gem.
We have two models, User and Thing, User has one Thing.
In the controller, what's the best practise in order to get the right Thing to create/delete if we assume that a User can only create/delete his own Thing.
Eg for create action.
OPTION 1 (standard) :
#thing = Thing.new(params[:thing])
#thing.save
And we set the user_id in the view.
OPTION 2 :
#thing = current_user.create_thing
And we don't bother about setting the user_id in the view.
Both works but I would like to know if one must be avoid or is better and why.
Thanks!
I personally think the second option is better because (as you say) you don't have to mess around with a user_id (neither in the view nor specifically within the controller).
The first option is only useful if you want to allow users to set things for other users than themselves. If you don't want to allow this, the first option even introduces a possible vulnerability. Malicious users can try exploiting the user_id field in the view. So, assuming users can only set their own things: definitely option 2.
If you are using devise gem, Its better to play with current_user. This will be more secured than passing users id.

How to create or modify actions in rails admin

I do not find any way in order to modify the behaviour of the existing methods in rails_admin. I am using rails 3.2 and integrated with PostgreSql.
I want to modify the behaviour of one of my method during the edit. I have a model of shipment_quotes and model has a charges column, by default this field is blank and I want if admin add any amount in this field then after submitting the form a mail will be shoot to particular user.
But I have not found any way to modify the admin methods.
Also I want to create new actions for particular model.
Please help me I really fed up with this. After so much googling I do not find any thing relevant.
Any help will be really appreciated...
Rails Admin wouldn't do this for you. You might as well create a callback method for shipment_quotes after create. I think something like this would help
class ShipmentModel < ActiveRecord::Base
after_create :verify_charges
private
def verify_charges
if !charges.blank?
# Then shoot an email
end
end
end
Rails admin would then just handle your CRUD.

How do I utilize user input without putting info into a Model?

This is an incredibly newbish question, but I can't seem to find the answer.
I'm building an app that utilizes external APIs heavily, and I'm fairly new to Rails, so it's still a little rough to get around. I can't, for the life of me, figure out how to accept user input and execute a function in my app without writing to a model.
For example, I just want to let a user type in a Twitter username and have it display on the page. I know how to make a form to cache the search in a model, but I can't figure out how to just... make a function happen on a page. I've been breaking my brains on this for several days now.
Please help? :/
You don't need a model to use Rails, but if you don't need ActiveRecord at all, you might benefit from a lighter framework like Sinatra. That doesn't answer your question, but it's worth thinking about if you really have no database requirement for your application.
It sounds like you're just trying to access non-resourceful user input, which is accessible in the controller via the params hash. So, assuming you have set up a valid route for the form action, you use your controller to extract GET or POST parameters.
For example:
# You define a non-resourceful route in routes.rb for your form action.
get 'twitternames/show'
# Form action directs user to GET the following route after filling in the form.
http://example.com/twitternames/show?user=foo
# The controller action extracts the data.
def show
#user = params[:user]
# render the view unless you tell rails to do something else
end
# show.html.erb
<%= #user %>
Creating the right route is the key. Once you've defined a route that can break a URL into the proper segments, the rest will fall into place.

rails3, params[:id] encryption

I trying to prevent url hacking, I passing an id to the url that the forms need, it works fine but if the user changes that value on the url it will send values to the wrong table.
<%= link_to '+ New Event',
{:controller =>'events', :action =>
'new', :company_id => company.id} %>
On the php world I used to encrypt that id ...how can I do this on rails3 or is there a better way ??
needless to say I sort of new to rails and I know a little bit of php
any help or suggestions will be greatly appreciated.
Even though this is an older question, it's a very worthwhile question. It is absolutely worthwhile to conceal the ID in the URL for, among other things, prevention of information disclosure.
For example, an application has a robust security model allowing users to only view resources to which they have rights. However, why should a user be able to look at the value of the ID in the URL and use it to deduce how many resources there are or, as the original questioner suggests, start trying to poke around with forced browsing.
The solution to this in rails turns out to be pretty simple. What I find works best is overriding to_param in the models, usually via a module in the lib directory and a before_filter in the application controller that decrypts the IDs.
For a walkthrough, have a look at this: http://www.youtube.com/watch?v=UW_s9ejrCsI
Rather than trying to encrypt or hide your company.id value, ask yourself what exactly it is that you want to prevent users from doing.
If you just want to prevent users from creating events associated with non-existant companies (by setting the id to a really high value for instance), then a simple
validates_presence_of :company
On the Event model would be fine.
If you only want users to be able to create events associated with companies that they work for, or have access for in some way, then you should create custom validations to verify that.
F

ROR 3 conditions in routes.rb

Is there a way to specify conditional statement inside routes.rb - I would like the root_path to depend on whether the user is signed in or not. perhaps there are other ways of accomplishing this?
Thanks!
Actually I think you can using advanced constraints it is documented here...
You would define a def matches?(request) to check if the user is signed in, and use two routes one when with a constraint of signed in and one when not.
Although I am not sure if the session is available when that custom constraint is executed.
Although I agree with SpyrosP it would be better to do it in the Controller.
No, you cannot do that. The routes do not rely on conditions that are based on model code. Anybody can call a route, so you cannot depend on that anyway.
Instead, just add a "before_filter :authenticate"(using sessions) on the controllers that you want to protect. If somebody tries to access your admin controller without being an admin, they will be redirected to login or anywhere you like.
I think the previous answers (suggesting a before_filter in the controller is more appropriate) are missing the OP's use case slightly. There are still advantages to doing it as a conditional route/advanced constraint. It doesn't replace having a before filter in the controller to prevent unauthorized direct access. But, for instance, having a redirect_to root_path route directly to e.g. a user's profile when he is signed in, or the front page when not, preserves flash messages that would otherwise be lost in a second redirect in the before filter. More elegant IMHO to use the advanced constraint approach (assuming of course that the session is in fact available when the custom contraint is tested). Not to mention, in this type of instance, why not save the extra redirect (since it involves a whole other HTTP(S) transaction)?
UPDATE:
If you're using Devise, this article describes an even better approach. Just implemented it myself and it works great, and it's clean.
Also, comments to explain down votes are always appreciated, not just for the author but for others who read the answer so they know why it might not be a reasonable response.