Permission in rails - ruby-on-rails

I have a jobs pages where users can create new jobs edit and destroy their jobs and I want to let user edit or destroy only their post only if are connected else they will returned to the job show page for this i have this code in my job controller
def require_login
#job = current_user.jobs.find_by_slug(params[:id])
redirect_to job_path if #job.nil?
end
before_action :login_required
def login_required
redirect_to new_user_session_path unless user_signed_in?
end
before_action :login_required, :require_login, only: [:edit, :update, :destroy]
the only part where this don't work is when i not connected and try to edit my job it redirect me to the log in form but after login it redirect me to the home page instead of the edit page

First of all, the code block you pasted looks weird, for three reasons:
Indentation is wrong
You have before_action :login_required twice and it's not even the same
From the methods names it's unclear what you want exactly
From what you wrote, you want a user to edit or destroy a job only if they are logged in - otherwise you want to send them to the jobs index page. If that's right, the code in your controller should look like this:
class JobsController < ApplicationController
before_filter :require_login, :only => [:edit, :update, :destroy]
def edit
# your code here
end
def update
# your code here
end
def destroy
# your code here
end
private
def require_login
redirect_to job_path unless user_signed_in?
end
end

Related

before_action with the same callback but different condition not working

this is my before_action in controller
before_action :redirect_to_home, unless: :logged_in?, only: %i[destroy]
before_action :redirect_to_home, if: :logged_in?, only: %i[new create]
My purpose is redirect to home when call new and create action for authenticated user and destroy for unauthenticated user
this is my redirect_to_home callback
def redirect_to_home
redirect_to root_path
end
this is my logged_in? method
def logged_in?
p 'HELLO FROM LOGGED_IN'
session[:user_id].present?
end
when I ran the destroy test spec nothing printed out to the console but when I swap the line and run the destroy test spec again everything looks fine but new and create test spec are broken.
Do you guys have any ideas?
Thanks
Ref this
Calling the same filter multiple times with different options will not work,
since the last filter definition will overwrite the previous ones.
You can do following
before_action :redirect_to_home, only: %i[new create destroy]
And in controller
def redirect_to_home
if logged_in?
redirect_to root_path
else
redirect_to destroy_path #You have to use actual destroy path here.
end
end
before_action doesn't prevent action to be executed if callback returns false.
You can make another method:
def ensure_user_is_logged_in
unless logged_in?
redirect_to_home
end
Then you can use it before_action like this:
before_action :ensure_user_is_logged_in, only: %i[new, create]
It will redirect to home if the user is not logged in.
You can refer to this for more info:
how to execute an action if the before_action returns false

What kind of logic should be in Rails before filter

Should I load and check the presence of the DB source in before filter?
In our application, we always load and check presence of DB source which has an id passed in by params. I'm not sure if this is a good pattern.
like:
before_action :set_org
private
def seg_org
#org ||= Organization.find params[:id]
resource_not_found unless #org
end
Yes, finding a record and setting it as an instance variable is a common convention for controller filters. Generally though, any piece of code that gets run for multiple actions is a good candidate. Say you want to redirect to the log in page if the current user is not logged in.
class UsersController < ApplicationController
before_action :require_login
before_action :set_user, only: [:show, :edit, :update, :destroy]
private
def require_login
unless logged_in?
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url # halts request cycle
end
end
def set_user
#user = User.find(params[:id])
end
end

before_action logs out user post update (using devise)

I'm trying to restrict access to the user edit page so that logged in user can only edit his/her own profile. FYI, I'm using Devise for user authentication, login, register, etc. This is supposed to be pretty easy to do with
class UsersController < ApplicationController
before_action :find_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = 'Profile Updated!'
redirect_to edit_user_path(#user)
else
render 'edit'
end
end
private
def user_params
# code left out... but pretty self explanatory right?
end
def find_user
#user = User.find(params[:id])
end
def correct_user
redirect_to(root_url) unless current_user == find_user
end
end
The weird thing is, when I have the before_action :correct_user, when the user updates... it logs the user out post-update! When I don't have the before_action :correct_user, it leaves the user logged in and redirects to edit page of the user. I tried manually signing the user in def update prior to redirecting to edit page, but it does not work. In fact, that isn't even the issue. When I compare the current_user and User.find(params[:id]), the current_user is logged in! But for some reason, having the before_action :correct_user there logs me out!
I've been banging my head on the wall for quite some time on this one. Can anyone help out? This is a Rails 4 app and am using the latest version of devise.
Thank you!
I'm not sure you really need the find_user method here.
class UsersController < ApplicationController
respond_to :html
def update
current_user.update_attributes user_params
respond_with current_user, location: [:edit, current_user]
end
private
def user_params
...
end
end
Seeing as you only let a user edit their own record, you can just use current_user in the update method.
Also, if you are happy to use the standard Rails convention for CRUD operations, then respond_to/with will save you a little time and code by implementing that for you. I used the location option otherwise respond_with defaults to the show page of the resource.

Update route in rails doesn't respond well to after_action?

class FrogsController < ApplicationController
before_action :find_frog, only: [:edit, :update, :show, :destroy]
after_action :redirect_home, only: [:update, :create, :destroy]
def index
#frogs = Frog.all
end
def new
#ponds = Pond.all
#frog = Frog.new
end
def create
#frog = Frog.create(frog_params)
end
def edit
#ponds = Pond.all
end
def update
#frog.update_attributes(frog_params)
end
def show
end
def destroy
#frog.destroy
end
private
def find_frog
#frog = Frog.find(params[:id])
end
def frog_params
params.require(:frog).permit(:name, :color, :pond_id)
end
def redirect_home
redirect_to frogs_path
end
end
Hi all. I was wondering if someone could explain to me why the update route in rails can't take my after_action of redirecting (custom made method on the bottom) it home. The error that I get when i include update in the after_action is "Missing template frogs/update".
This is going to cause me to manually add a redirect_to frogs_path inside the update method.
thanks!
The after_action callback is triggered after the action has run its course. You cannot use it to render or redirect. Do that within the action itself by calling the method:
def update
...
redirect_home
end

Multiple before_filter statements for correct_user and admin

I have a Group resource that I'm trying to set up with proper authorizations.
The authorization logic I'm trying to implement is this:
Only group members should be able to view their group.
An admin can view any group, as well as take other actions.
I'm attempting to do this with the following before_filter statements in the group controller:
before_filter :signed_in_user
before_filter :correct_user, only: :show
before_filter :admin_user, only: [:show, :index, :edit, :update, :destroy]
Correct_user works as I have verified that only group members can view their group. However, what I want to happen is for the admin :show clause to override this, so that an admin can view any group. Currently that is not working. I'm guessing I have something wrong here with my filter ordering and options.
Can someone tell me where I've gone wrong?
EDIT
Adding my method code per Amar's request:
private
def correct_user
# User has to be a member to view
#group = Group.find(params[:id])
redirect_to(root_path) if #group.members.find_by_member_id(current_user).nil?
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
Update the correct_user method or create another method with the following definition, remove show from other filter and add before_filter with new method.
def correct_user
#group = Group.find(params[:id])
redirect_to(root_path) if #group.members.find_by_member_id(current_user).nil? && !current_user.admin?
end

Resources