devise roles: different roles, in some cases same rights - ruby-on-rails

I have two roles in devise. The first is the admin and the second the normal user-role.
Now I´d like to give these two groups in some cases same rights with before filters.
How does this work?
I have:
before_filter :authenticate_user!, :only => [:new, :create]
before_filter :authenticate_admin!, :only => [:new, :create, :edit, :update, :destroy]
But now only a user can :new and :create...the admin not..
What I have to do here?
Thanks,
Mattherick

I haven't yet used Devise personally, so this is only to point you in the right direction. It might not work exactly right.
before_filter :authenticate_user_or_admin, :only => [:new, :create]
before_filter :authenticate_admin!, :only => [:edit, :update, :destroy]
# ...
protected
def authenticate_user_or_admin
unless user_signed_in? or admin_signed_in?
# Redirect somewhere else
end
end

Related

Rails - Authentication Devise - Problem About authenticate_user

please !
I'm taking first steps in Ruby on Rails and I have a problem for to implements authentication with Devise. In short , this is scenario:
I want that the users can register a new user only inside the aplication, in other words, only after to authenticate. So I used the line of code above,
authenticate_user!(force:true) for to protect the route of register.
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
before_action -> {authenticate_user!(force:true)}, only: [:new, :create, :destroy]
...another methods without modification
And my file routes
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions',
passwords: 'users/passwords',
registrations: 'users/registrations',
confirmations: 'users/confirmations'
}
resources :enrolls
resources :students
resources :trainings
resources :instructors
# Certificates
get 'certificates/:id', to: 'certificates#index'
# Dashboard
get 'dashboard', to: 'dashboards#index'
root :to => redirect('/dashboard')
end
So, After this , I can to authenticate and to protect all routes, but after authenticate,
the route /users/sign_up(.:format) for registration don´t working,dont open the form for register, this route are protected even after authentication.
When I type this route , the application redirect again for dashboard (root).
Can someone please help me?
Think it's a hard task for a newcomer.
Let me explain why it doesn't work, take a look at the definition of Devise::RegistrationsController https://github.com/heartcombo/devise/blob/main/app/controllers/devise/registrations_controller.rb
prepend_before_action :require_no_authentication, only: [:new, :create, :cancel]
so in your controller you'd need to do:
class Users::RegistrationsController < Devise::RegistrationsController
skip_before_action :require_no_authentication, only: [:new, :create]
...
end
This change will basically remove the before_action defined in Devise::RegistrationsController and you won't be redirected anymore.
For me is working , my code is like this, Thank for your help Adam!
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
before_action -> {authenticate_user!(force:true)}, only: [:new, :create, :destroy]
skip_before_action :require_no_authentication, only: [:new, :create]

Rails error Couldn't find Blog with 'id'=new

I have a weird error when I want to redirect users to the root_url when they try to access blogs/new url in my app.
My routes are
resources :blogs, only: [:index, :show] do
resources :comments, only: [:create]
end
namespace :admin do
resources :blogs
resources :users, only: [:index, :show]
resources :comments, only: [:create, :new, :destroy]
end
My non-admin blogs controller looks like this:
class BlogsController < ApplicationController
before_action :set_blog, only: [:show]
def show
unless #blog
redirect_to blogs_path
flash[:notice] = "You are not authorized to create a post."
end
end
def index
#blogs = Blog.all
end
private
def set_blog
#blog = Blog.find(params[:id])
end
end
I get the error Couldn't find Blog with 'id'=new.
In rails, the priority of routes goes from top to bottom. Meaning, when you try to hit /blogs/new, the route gets matched with the show action of blogs defined in the top of your routes.rb.
blogs/new gets matched with /blogs/:id which is mapped to blogs#show action.
In the set_blog method, params[:id] is new and since there is no record with the id of new, you're getting that weird error.
How to get around this? Change the priority of your routes.
Move the following block below the admin namespaced routes.
namespace :admin do
resources :blogs
resources :users, only: [:index, :show]
resources :comments, only: [:create, :new, :destroy]
end
resources :blogs, only: [:index, :show] do
resources :comments, only: [:create]
end
By the way, your question says that you want to avoid non-admin users to access blogs#new. If that's the case, you should try to hit /admin/blogs/new and not /blogs/new.
If you had done that, you wouldn't have gotten the error in the first place. But still, its good to know about the priority of routes in rails.
Hope this helps!

No route matches when trying to sign up

I'm having troubles with routes in Ruby on Rails. I've configured routes this way
resources :users do
collection do
resource :registrations, only: [:show, :create]
resource :sessions, only: [:new, :create, :destroy]
resource :confirmations, only: [:show]
end
end
And I have a RegistrationsController where I have two endpoints (new, create)
class RegistrationsController < ApplicationController
skip_before_filter :authenticate!
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = t("registrations.user.success")
redirect_to :root
end
end
end
But when I do rails s and I put localhost:3000/users/registrations/create or new I get a "no route matches". And I think the route exist because If I do raake routes I get this
registrations POST /users/registrations(.:format) registrations#create
GET /users/registrations(.:format) registrations#show
I know it should be a silly mistake but I don't get it. I appreciate any help
When you define routes for registrations, you're limiting it to just [:show, :create]:
resource :registrations, only: [:show, :create]
But your controller (correctly!) is presuming that there are two routes: new (to show the registration form) and create (to create the new user). You need to change your routes so that they match your controller actions:
resources :users do
collection do
resource :registrations, only: [:new, :create] # Updated this line!
resource :sessions, only: [:new, :create, :destroy]
resource :confirmations, only: [:show]
end
end

Rails: how to apply authenticate_user filter only for mobile views

Currently I got the following code piece in SomethingController:
class SomethingController < ApplicationController
skip_filter :authenticate_user!, :only => [:new, :create, :edit, :update]
#...
#new
#create
#edit
#update
end
Currently: We wanted unauthenticated users to be able to create or update Something objects.
The problem: Due to the different nature of our mobile phone authentication, we want to restrict unauthenticated mobile phone user not to be able to use this controller actions before they sign in/up. Can we add some condition to the filter, like:
skip_filter :authenticate_user!, :only => [:new, :create, :edit, :update], :format=>:html
skip_filter :authenticate_user!, :only => [], :format=>:mobile
If that is not possible, what is the best practice? Is this acceptable?
def new
if current_user.nil?
#redirect to sign_in/up actions
end
#rest of the method
end
Skip the filter only for non mobile requests. Something like below.
class SomethingController < ApplicationController
skip_filter :authenticate_user!, :only => [:new, :create, :edit, :update], :unless => :mobile?
#...
#new
#create
#edit
#update
def mobile?
#implementation here depends on how you do the mobile detection
end
end

Model level method to call in before_filter

I am working in rails 2, I have a model level method, which i want to call in before_filter. How can i do this?
I tried this way, but its not working
before_filter :LmsUser.can_edit_update, :only => [:new, :create, :edit, :update, :destroy]
You should add a method to your controller and use that as the before filter. For example:
class MyController < ApplicationController
before_filter :check_permissions,
:only => [:new, :create, :edit, :update, :destroy]
private
def check_permissions
unless LmsUser.can_edit_update
# redirect_to, render, or raise
end
end
end
See the filters section of the Action Controller Overview guide for more information.

Resources