I'm new to Ruby and Rails, so I'm trying to do something that might be easy on other languages but I can't deal with it in Rails:
I have designed a couple tables in the database that match each controller and action name. That way, if I wand to administer special permissions for a user, I just ad the proper action to the proper controller in the database, and with the method check_permissions
, I know if the user can execute the action or is redirected to a standard "forbidden" page.
So for example, here's my code for the users CRUD:
First I created a check_permissions
method in application controller, which grabs the current action, user and controller, and checks authorization rights against the DB:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include SessionsHelper
def self.check_permissions
remember_token = User.digest(cookies[:remember_token]) # encripto el token para poder buscarlo en la DB, ya que ahi se guarda encriptado.
@current_user ||= User.find_by(remember_token: remember_token)
redirect_to signin_path if (@current_user == nil) or (User.find_by_sql("select * from view_userpermissions where user_id = #{@current_user.id} and pagecontroller='#{self.controller_name}' and accion='#{self.action}' ").count < 1)
end
...
...
Then in each controller, I use the before_action :check_permissions
filter to redirect the user in case is not authorized to access the required content:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action self.comprobar_permisos
def index
@users = User.paginate(page: params[:page])
end
...
...
The code flow seems to work very well, but the problem is rails cookies hash is not recognized when before_action filter is called.
I also tried using session, but happens exactly the same.
The first thing that comes to my mind is that in Rails architecture, neither session or cookies hashes are instanced by the moment the filter is executed, and then when the application controller tries to access them, an error is displayed:
Routing Error undefined local variable or method `cookies' for UsersController:Class Rails.root: C:/Users/daniel.tenzi/proyectos/MicroEstudio Application Trace | Framework Trace | Full Trace app/controllers/application_controller.rb:11:in `check_permissions' app/controllers/users_controller.rb:3:in `' app/controllers/users_controller.rb:1:in `' Routes Routes match in priority from top to bottom Helper HTTP Verb Path Controller#Action Path / Url pagecontrollers_path GET /pagecontrollers(.:format) pagecontrollers#index POST /pagecontrollers(.:format) pagecontrollers#create new_pagecontroller_path GET /pagecontrollers/new(.:format) pagecontrollers#new edit_pagecontroller_path GET /pagecontrollers/:id/edit(.:format) pagecontrollers#edit pagecontroller_path GET /pagecontrollers/:id(.:format) pagecontrollers#show PATCH /pagecontrollers/:id(.:format) pagecontrollers#update PUT /pagecontrollers/:id(.:format) pagecontrollers#update DELETE /pagecontrollers/:id(.:format) pagecontrollers#destroy permissions_path GET /permissions(.:format) permissions#index POST /permissions(.:format) permissions#create new_permission_path GET /permissions/new(.:format) permissions#new edit_permission_path GET /permissions/:id/edit(.:format) permissions#edit permission_path GET /permissions/:id(.:format) permissions#show PATCH /permissions/:id(.:format) permissions#update PUT /permissions/:id(.:format) permissions#update DELETE /permissions/:id(.:format) permissions#destroy groups_path GET /groups(.:format) groups#index POST /groups(.:format) groups#create new_group_path GET /groups/new(.:format) groups#new edit_group_path GET /groups/:id/edit(.:format) groups#edit group_path GET /groups/:id(.:format) groups#show PATCH /groups/:id(.:format) groups#update PUT /groups/:id(.:format) groups#update DELETE /groups/:id(.:format) groups#destroy users_path GET /users(.:format) users#index POST /users(.:format) users#create new_user_path GET /users/new(.:format) users#new edit_user_path GET /users/:id/edit(.:format) users#edit user_path GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy empresas_path GET /empresas(.:format) empresas#index POST /empresas(.:format) empresas#create new_empresa_path GET /empresas/new(.:format) empresas#new edit_empresa_path GET /empresas/:id/edit(.:format) empresas#edit empresa_path GET /empresas/:id(.:format) empresas#show PATCH /empresas/:id(.:format) empresas#update PUT /empresas/:id(.:format) empresas#update DELETE /empresas/:id(.:format) empresas#destroy sessions_path POST /sessions(.:format) sessions#create new_session_path GET /sessions/new(.:format) sessions#new session_path DELETE /sessions/:id(.:format) sessions#destroy root_path GET / users#index signup_path GET /signup(.:format) users#new signin_path GET /signin(.:format) sessions#new signout_path DELETE /signout(.:format) sessions#destroy
But if my guess is true, why would Rails says routing error
?
I've been stuck here at least a week trying to find anything that helps me move forward but no luck yet.
What am I doing wrong? Any help will be highly appreciated!
PS: I've seen auth frameworks like Cancan, but don't want to use any of that, this should be easier and more flexible.
Thank you!
...User.find_by_sql("select * from view_userpermissions where user_id = #{@current_user.id} and pagecontroller='#{self.controller_name}' and accion='#{self.action}' ").count < 1)
can be rewritten as... ViewUsercondition.where(user_id: @current_user.id).where(pagecontroller: self.controller_name).where(accion: self.action)
This is shorter, cleaner, easier to read and survives changing the database technology should you ever need to do that. – A Fader Darkly