I'm currently trying to make it so that if a user is not an admin they cannot get onto the 'create & edit' pages and also cannot destroy entries.
I have this method within my controllers
def must_be_admin
unless current_user && current_user.admin?
redirect_to root_path, notice: "Admin Needed."
end
end
and I call it like so:
before_filter :must_be_admin, only: [:edit, :destroy, :create]
This seems to let unlogged in users on the create page, but doesn't let them do the actual create action. Is there anyway to NOT allow users on the actual pages as well?
Essentially don't allow any users that aren't admin to
create/edit/destroy (as well as not let them on the actual pages) and
just reroute them back to index.
Yes if you restrict the new and edit actions as well they will not be able to see any of the pages. If you have a standard CRUD controller just eliminate the "only" option in your before_action and all non-admins will be blocked.
You have to remember that while blocking the create action you are not blocking the "new" actions page displaying everything. Blocking the 'new' action as well will stop them from even seeing the page.
Related
i have an application where i'm using devise for authentication,
I have a USER model, those users can create publications, some publications that can be seen by all the users I called Articles and I represent them in the ARTICLE model, the same users can also create Notes, I have represented them in the NOTE model, but Unlike publications, these Notes can only be viewed or accessed by the users who created them and not by other users, for example:
myapp / articles / 5 (all users can access)
myapp / notes / 5 (can only be accessed by the user who created them)
The controller for the index view I have it like this:
def index
#notes = current_user.notes
end
def show
#note = Note.find params[:id]
end
The problem is that I can't get only creator users to access the notes in the show view, since by changing the ID number in the browser, another user accesses the note that does not correspond to him.
In the Index view I had no problem because I can get the list of the notes that were created by its users.
Any suggestion?
You could do a before_action to check if the note does not belong to the user who tried to access it.
Something like:
class NotesController < ApplicationController
before_action :set_note, only: :show
before_action :verify_permission, only: :show
# Your code here...
private
def set_note
#note = Note.find(params[:id])
end
def verify_permission
redirect_to notes_path if !user_signed_in? || #note.user != current_user
end
end
Explaining the code:
set_note makes your code cleaner. If you're going to use the same #note = Note.find(params[:id]) in other actions (edit, update or destroy) you could simply add them to the before_action callback and avoid using the same code 4 times.
verify_permission checks if the user is logged in and if the note belongs to the user who created it. If one of these conditions is not matched, the user is redirected to the notes path (it could be whatever you want). If you would also like to run this verification on edit or destroy, just add the keys on the before_action as well.
An example if you want to verify the permission on more than 1 action:
before_action :verify_permission, only: %i[show edit update destroy]
In my app, after a user logs in, he is redirected to the AccountsSelection controller. In there, I have an index action that basically will get all the potential accounts a user can use, and display them in a index view.
def index
#accounts = current_user.eligible_accounts
end
In that page the user can click in one of the accounts, and that should go to one of the actions in the controller, that will set this in the session:
def show
session[:selected_account] = params[:account_id]
redirect_to account_path
end
Right now I have made that action to be show (so the selection of the account is doing a GET request, but I am not sure if this is a RESTful way of approaching this). From my point of view this is not a PUT/POST because I am not changing any resource or creating any resource, but it seems weird to be using the show action to just set a session.
What would be a proper way of handling this? It is correct to use show?
It is not recommended to use session in this case. So the standard approach is to create a before_action to set the account_id.
Use like this:
before_action :set_account, only: [:show]
and create the function in private as:
private
def set_account
account_id = params[:account_id]
end
Hope this helps.
I have a job show page where I want only sign users to apply and if user is not sign in I will show him the apply button and when they click in the button they will redirected to the sign up page and after sign up they will redirected to the job show page. I'm wondering how can I achieve this?
I was thinking to separate the job into 2 model job-details and job_apply and in the job_apply controller put this before_action :authenticate_user!, but I'm wondering if there another solutions?
You don't need to create another action. Don't add before_action :authenticate_user! for the show action.
You need to add before_action :authenticate_user! for the apply action. once the non-signed in user clicks the apply action, He/She will be redirected to sign_in.
I just use a helper method in application controller. This code obviously needs a current_user helper method as well.
def confirm_logged_in
if !current_user
redirect_to '/sessions/new'
flash[:login_failure] = 'You must be logged in to see this page'
session[:return_path] = request.original_url
end
end
then in your sessions controller use something like
redirect_to session[:return_path] || root_path
I'm sort of new to rails, what I want to to is protect users profile
what I mean is if user 1 login and go to edit his profile he can, but also if he change on the url to user to # 2 they can also change their information
localhost:3000/users/2/edit
I'm a little lost, any help will be greatly appreciated, or suggestions of good books/blogs
As part of authentication add a session variable, session[:user_id] = User.Authenticate(params[:user][:username], params[:user][:password) (this is the general pattern, you need to add another resource for authentication).
Then add a before_filter function to your controller and check if session[:user_id] == params[:id]. Look at it here: before_filter
The Rails Security Guide is probably a good place to start
Just in case this is useful to someone, something that I came across when testing my app was although users that hadn't signed in couldn't access restricted content, once a user was signed in, they could change the url to a another users id, eg.
/users/3 and it would then show that users home page. So any user could look at any other user, which wasn't what I wanted.
To get around this, I changed the user controller to secure against this:
class UsersController < ApplicationController
#first call the correct_user function before allowing the show action to proceed
before_filter :correct_user, only: [:show]
...
def show
#do whatever here
end
...
private
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
I am fairly new to Ruby On Rails and right now I am doing a simple app. In this app a user can create many items and I use devise for authentication. Ofcourse I want to make sure that you are the owner in order to delete items (Teams, Players etc) and the way I do it now is:
def destroy
#team = Team.find(params[:id])
if current_user.id == #team.user_id
#team.destroy
redirect_to(teams_url, :notice => 'The team was deleted.')
else
redirect_to root_path
end
end
Is this the best way? I was thinking about putting a method in the model but I am not sure I can access current_user from there. I was also thinking about a before_filer, something like:
before_filter :check_ownership, :only => [:destroy, :update]
I that case and if I want to code only one method for all objects (all objects this relates to have a "user_id"-field)
In my application controller I put:
before_filter :authorize
def authorize
false # Or use code here to check if user is admin or not
end
Then I override the authorize method in my actual controller to allow access to various actions.
You're looking for an authorization solution on top of your authentication (devise)
You can't access current user in the model no. I've had a fair amount of success using Makandra's Aegis for authorization. It allows you to create roles specify permissions attributed to each role. The docs are pretty good and I know it works fine with Devise, it's pretty agnostic that way, I've also used it with Clearance. It also passes an implicit "current_user" to your permissions so you can specify and check that your current user can take appropriate actions.