Rails: before_action :authenticate_admin! doesn't work - ruby-on-rails

I'm doing this in routes.rb:
devise_for :admins, :skip => [:registrations], controllers: {sessions: 'admins/sessions'}
devise_scope :admin do
get "admins/home"=> "admins/sessions#home", :as => "admin_home"
end
But when I put the before_action :authenticate_admin! in the sessions controller and open the admins/home the login screen doesn't appear, no errors pop up neither. I get full access to the page without having to log in!
class Admins::SessionsController < Devise::SessionsController
before_action :configure_sign_in_params, only: [:create]
before_action :authenticate_admin!
def home
end
def new
super
end
def create
super
end
def destroy
super
end
protected
def configure_sign_in_params
devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
end
end
Any ideas what I might be doing wrong?

Your defined route to create session in home action.So change home action
class Admins::SessionsController < Devise::SessionsController
before_action :configure_sign_in_params, only: [:create]
def home
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in)
sign_in(resource)
respond_with resource, location: after_sign_in_path_for(resource)
end
def new
super
end
# override method here
def create
end
def destroy
super
end
protected
def configure_sign_in_params
devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
end
end
NOTE: And put this in application controller
before_action :authenticate_admin!

Related

What is the difference between before_action and prepend_before_action in Rails?

My codebase contains callbacks like
prepend_before_action :authenticate_api_user! and
before_action :authenticate_api_v1_user!
What is the difference between these two?
Generally before_action runs before every action to a method and
prepend_before_action does what it says. It just add your definition at index zero.
Here is a great use case to prove the same:
class ConfuseUsersController < ApplicationController
prepend_before_action :find_user, only: [:update]
prepend_before_action :new_user, only: [:create]
before_action :save_and_render
def update
end
def create
end
private
def find_user
#user = User.find(params[:id])
end
def new_user
#user = User.new
end
def save_and_render
persited = #user.persited?
#user.assign_attributes(user_params)
if #user.save
redirect users_path(#user)
else
render (persited ? :edit : :new)
end
end
end
before_action :save_and_render this makes save_and_render to get called before every action.
prepend_before_action :find_user, only: [:update] This prepends find_user function to get called before save_and_render
Another example:
We have an ApplicationController where...
class ApplicationController < ActionController::Base
before_action :one
before_action :three
end
Now in any controller if we want to execute any other method for e.g. two before three you can use prepend_before_action like
prepend_before_action :three, :two
class AdminsController < ApplicationController
prepend_before_action :three, :two
end
Now before three gets executed two will get execute and then three for this specific method.

ruby - run http://localhost:3000/admin/users but redirect_to http://localhost:3000/admin/login

I am new in Ruby on Rails.
I want to run http://localhost:3000/admin/users to see users index page.
But when I run this link, it guide me to http://localhost:3000/admin/login.
Is there something wrongs with my route setting?
Rails.application.routes.draw do
get 'users/new'
get 'users/show'
if Rails.env.development?
mount LetterOpenerWeb::Engine, at: '/letter_opener'
end
root to: 'helps#top'
# admin login
get 'admin/login', to: 'admin/login#index', as: 'admin/login'
get 'admin/logout', to: 'admin/login#logout'
post 'admin/login/login'
get 'admin', to: 'admin/projects#index', as: 'admin_top'
namespace :admin do
resources :users, only: %i(index new create)
resources :projects do
resources :project_users
resources :project_comments
end
resources :images
resources :categories
resources :campanies
end
end
users_controller.rb
class Admin::UsersController < AdminController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
end
#Post /admin/projects
def create
#user = User.new(user_params)
if #user.save
flash[:notice] = 'User saved successfully'
redirect_to :back
else
flash[:alert] = #user.errors
binding.pry
render :new
end
end
def update
end
def destroy
end
private
def set_user
#user = User.find(params [:id])
end
def user_params
params.require(:user).permit(:campany_id, :name, :email, :password_digest, :profile, :prefecture_id, :address)
end
end
Thank you!
Your UsersControllers is under the admin namespace, that's to say you must be logged in order to access to this.
If you want to have access without validating the user is currently logged in, then you'll have to remove the constraint or verification to the controller or to make a new controller and index method which point to /admin/users but this time without the user verification.
That's:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
...
def index
#users = User.all
end
...
end
# config/routes.rb
get '/users', to: 'users#index'
'/users' or '/admin/users' as you want to do it, but if you use the last one then any person must infer that's a restricted resource .

Rails, duplicate code refactoring

How can I refactor this similar snippets of code in rails controller?
app/controllers/albums_controller.rb:58…62 < >
def set_album
if current_user.admin?
#album = User.find(params[:user_id]).albums.find(params[:id])
else
#album = current_user.albums.find(params[:id])
end
end
app/controllers/articles_controller.rb:45…49 < >
def set_article
if current_user.admin?
#article = User.find(params[:user_id]).articles.find(params[:id])
else
#article = current_user.articles.find(params[:id])
end
end
app/controllers/photos_controller.rb:55…59 < >
def set_photo
if current_user.admin?
#photo = User.find(params[:user_id]).photos.find(params[:id])
else
#photo = current_user.photos.find(params[:id])
end
end
controllers/concerns/user_resource.rb
module UserResource
extend ActiveSupport::Concern
included do
before_action :set_resource , only: [:edit, :update, :destroy]
before_action :signed_in_user, only: [:new, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
end
def set_resource
association = controller_name.classify.downcase
resource = current_user.admin? ? User.find(params[:user_id]) : current_user
resource = resource.send(association.to_s.pluralize).find(params[:id])
instance_variable_set("##{association}", resource)
end
def correct_user
association = controller_name.classify.downcase
redirect_to root_path unless admin_or_current?(instance_variable_get("##{association}").user)
end
end
then, in {photos, albums, articles}_controller.rb
include UserResource
One way to do this is to create a new controller:
class ResourceController < ApplicationController
before_filter :set_resource, only: [:show, :edit, :update, :destroy]
private
def set_resource
user = current_user.admin? ? User.find(params[:user_id]) : current_user
resource = user.send(controller_name.to_sym).find(params[:id])
instance_variable_set("##{controller_name.singularize}", resource)
end
end
then your albums_controller.rb:
class AlbumsController < ResourceController
# use #album in show, edit, update, and destroy
end
articles_controller.rb:
class ArticlesController < ResourceController
# use #article in show, edit, update, and destroy
end
photos_controller.rb:
class PhotosController < ResourceController
# use #photo in show, edit, update, and destroy
end
It would a good idea to use metaprogramming here, I mean something like:
def set_resource(association_singular) # e.g. :photo
resource = current_user.admin? ? User.find(params[:user_id]) : current_user
resource = resource.send(association.to_s.pluralize).find(params[:id]) )
instance_variable_set("##{association}", resource)
end
Then, within a controller either before_filter only: [:action] or
def action
# ...
set_resource(:photo)
# ...
end

Rails cancan issue with before_filter

I recently integrated cancan (1.6.9) into my Rails (3.2.10) project for authorization, and I'm having an issue with manually loading a resource in a before_filter. Here's a brief description of my scenario.
In config/routes.rb, I have the following entries...
resources :users
match '/profile', :to => 'users#show'
Here's what my users_controller.rb looks like...
class UsersController < ApplicationController
before_filter :load_show_resource, :only => :show
load_and_authorize_resource
...
def show
end
...
private
def load_show_resource
#user = params[:id] ? User.find(params[:id]) : current_user
end
end
If my current_user's id is 1, this code will let me access localhost:3000/users/1 but not localhost:3000/profile.
The entry in my cancan ability.rb class that's blocking this access is seen below - it's the cannot section. If I comment out the cannot entry, both urls work.
...
can [:show, :update], User, :id => user.id
cannot [:show, :update, :destroy], User do |u|
u.site_id != user.site_id
end
....
Shouldn't cancan use the resource that's being manually loaded in the before_filter for the show action regardless of whether or not params[:id] is present?
Interestingly enough, if I modify my users controller (see below) to use skip_load_and_authorize_resource :only => :show and manually calling authorize! in the show action, both urls work. Also, if I remove cancan altogether both urls work.
class UsersController < ApplicationController
load_and_authorize_resource
skip_load_and_authorize_resource :only => :show
...
def show
#user = params[:id] ? User.find(params[:id]) : current_user
authorize! :show, #user
end
...
private
def load_show_resource
#user = params[:id] ? User.find(params[:id]) : current_user
end
end
So, my question is why does what's explained in the Override loading in the cancan documentation, not work in this situation?
Thanks!
# controller
class UsersController < ApplicationController
load_and_authorize_resource, :except => :show
# skip_load_and_authorize_resource :only => :show
...
def show
#user = params[:id] ? User.find(params[:id]) : current_user
authorize! :show, #user
end
...
end
# ability.rb
can [:show, :update, :destroy], User do |u|
u.id == user.id && u.site_id == user.site_id
end

Multi-form in rails using Wicked Gem and Devise

I am trying to set a multi-form login system using the Wicked gem. I have devise installed up and running correctly, when following these steps:http://railscasts.com/episodes/346-wizard-forms-with-wicked.
I'm not being redirected to the user_step_paths? everything is done as stated in the tutorial but, I'm guessing because I'm using devise i need to do it in a controller inherited by devise? my code is below for the controllers:
users_controller.rb
class UsersController < Devise::RegistrationsController
def new
#user = User.new
end
def create
#user = User.new(params[:sign_up])
if #user.save
session[:user_id] = #user.id
redirect_to user_steps_path
else
redirect_to new_user_registration_path
end
end
end
users_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :education, :social
def show
render_wizard
end
end
routes
get 'pages/home'
devise_for :users, :controllers => { :registrations => 'users'}
resources :user
resources :user_steps
1.Needed a update method in the controller and needed to define user in the show method:
def show
#user = current_user
render_wizard
end
def update
#user = current_user
#user.update_attributes(user_params)
render_wizard #user
end
2.Needed to generate the devise controllers:
rails generate devise:controllers [scope]
3.Update the registration_controller for devise
class Users::RegistrationsController < Devise::RegistrationsController
# before_filter :configure_sign_up_params, only: [:create]
# before_filter :configure_account_update_params, only: [:update]
# GET /resource/sign_up
def new
super
end
# POST /resource
def create
super
end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
def update
super
end
# The path used after sign up.
def after_sign_up_path_for(resource)
user_steps_path
end
# The path used after sign up for inactive accounts.
def after_inactive_sign_up_path_for(resource)
super(resource)
end
end
4.This controller is invalid, you need to use the generated controllers by devise:
class UsersController < Devise::RegistrationsController

Resources