I'm using Pundit to authorize actions in my controllers. My first try was to authorize the model in an after_action hoook:
class CompaniesController < InheritedResources::Base
after_action :authorize_company, except: :index
def authorize_company
authorize @company
end
This let me use the default controller actions which define @company
so I wouldn't hit the database twice. But, this is bad for destructive actions because it's going to not authorize the action after I've already messed up the database.
So, I've changed to using a before_action
hook:
class CompaniesController < InheritedResources::Base
before_action :authorize_company, except: :index
def authorize_company
@company = Company.find(params.require(:id))
authorize @company
end
Now, I'm not allowing unauthorized people to delete resources, etc... but I'm hitting the database twice. Is there anyway to access @company
without hitting the database twice?
Since your asking for the "rails way" this is how you would set this up in "plain old rails" without InheritedResources
.
class CompaniesController < ApplicationController
before_action :authorize_company, except: [:new, :index]
def new
@company = authorize(Company.new)
end
def index
@companies = policy_scope(Company)
end
# ...
private
def authorize_company
@company = authorize(Company.find(params[:id]))
end
end
If you really want to use callbacks you would do it like so:
class CompaniesController < ApplicationController
before_action :authorize_company, except: [:new, :index]
before_action :authorize_companies, only: [:index]
before_action :build_company, only: [:new]
# ...
private
def authorize_company
@company = authorize(Company.find(params[:id]))
end
def authorize_companies
@companies = policy_scope(Company)
end
def build_companies
@company = authorize(Company.new)
end
end
Yeah you could write a single callback method with three code branches but this has lower cyclic complexity and each method does a single job.