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.
Related
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.
I'm sharing one database for two web applications. The User model is already being used for one of these apps, so, in order to sign in to the other one, I had to create another model to avoid mixing users info.
I could make Devise work for this new model, called SystemUser. The problem is now I'll have to use every variable with another name. For example: current_system_user, system_user_signed_in?, etc. I'm using these variables, with their original name, across the whole application, and I would like to know if there's a way to avoid overwriting it. For example: by creating a method called current_user that returns current_system_user, and that way with the other variables mentioned before.
I think this should do the trick:
devise_for :users, class_name: 'SystemUser'
have you considered using CanCan for roles?
https://github.com/ryanb/cancan
I could finally solve the issue by generating the Devise views again. I don't know why, but the devise/sessions folder was missing, and it was doing it with another view, and when I started using it, it worked.
Thanks anyway.
I am using rails 3.2.7, mongoid 3, and i am trying to use devise for users accounts.
Before i'll start: i was searching a lot for my problem, and i read many tutorials, byt none fit to my need.
I have similar problem like devise and multiple “user” models
but i am using mongodb so i think the problem is not exacly the same.
I have 3 types of users":
Manger which can have many places and can manage them(edit info).
User which can search for places(even no user can) and create their places lists. Also user can comment and note the places.
Administrator who can edit/delete anythig, so admin is a god.
So, all of them have different data(except of login info) and i don't know what solution is the best.
STI would be good if they would have the same data, and different actions, but data are different too(but i am using mongoid, so maybe it would be fine?)
Single user model with roles is another solution but i don't know how to store different data, maybe with polymorphic? I don't fully understand how it should be implemented with devise and maybe cancan.
Maybe there is third?
I know what is STI, polymorphic associations, also how to implement roles with CanCan, but the problem is that i dont't know how to connect them with devise?
If there would be few sign in forms or one, it doesn't matter. I don't have to use devise either.
I found few tutorials/examples how to use devise, monogid, roles for multi-users applications, but they are when users store the same data, so they don't fit for me.
Can you give me advice, or a maybe a link which could help me?
Thanks for help :)
I would recommend building different controllers for different use cases. Don't build dependencies of different views inside the data. This way you are free to use the data for other use cases or other user groups without changing it directly.
Simply create controllers for the different use cases. This way you can change them any time without changing your data model.
For example, suppose I had a blog and anybody could read the articles, read the comments, and flag any comment as inappropriate. How do I prevent non-signed-in users from clicking the "Flag Comment" link more than once?
The "Flag Comment" link would be tied directly to a controller method for a Comment model.
I'm new to the idea of sessions and cookies (as well as Rails in general). I've read this on Sessions but I'm afraid I'm still a little confused.
I've considered creating a Base class called Guest, but I was wondering if I could avoid this and instead utilize session or cookies temp data.
Thanks in advance.
The basic idea could be the following (sorry, no code yet):
Define which information should be stored in a session and / or a cookie. I think it should be the id of the comment for each flagged comment. Store them in a hash like structure.
Make the link to flagging a comment depending on the content of the cookie. Something like that:
...
= link_to('flag comment', flag_comment_path(comment.id)) if ! cookies[:flagged_comments] || ! cookies[:flagged_comments][comment.id]
Set the cookies hash value when a comment is flagged (use here the local variable comment, this has to be set or known somewhere):
cookies[:flagged_comments] = Hash.new if ! cookies[:flagged_comments]
cookies[:flagged_comments][comment.id] = comment.id
I don't know if the code will work, but the idea should be clear. And yes, do that only to anonymous users (more dependent UI and controller functionality).
One more thing: I don't think you should use the session and the cookies for storing this information. And due to the fact that you have to notice when someone flags a comment in 2 different sessions, go with the cookies only.
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.