Module: LoadAndAuthorizeResource::ClassMethods

Defined in:
lib/load_and_authorize_resource.rb

Instance Method Summary collapse

Instance Method Details

#authorize_parent(*names) ⇒ Object

Macro sets a before filter to authorize the parent resource. Assumes ther resource is already set (in a before filter).

class NotesController < ApplicationController
  authorize_parent :group
end

If @group is not found, or calling current_user.can_read?(@group) fails, an AccessDenied exception will be raised.

If the parent resource is optional, and you only want to check authorization if it is set, you can set the :shallow option to true:

class NotesController < ApplicationController
  authorize_parent :group, shallow: true
end

Parameters:

  • options (Hash)

    a customizable set of options



145
146
147
148
149
150
151
# File 'lib/load_and_authorize_resource.rb', line 145

def authorize_parent(*names)
  options = names.extract_options!.dup
  required = !(options.delete(:shallow) || options.delete(:optional))
  permit = options.delete(:permit) || :read
  save_nested_resource_options(:auth, names, required: required, permit: permit)
  before_action :authorize_parent, options
end

#authorize_resource(options = {}) ⇒ Object

Checks authorization on the already-loaded resource.

This method calls current_user.can_<action>?(@resource) and raises an AccessDenied exception if the answer is 'no'.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :except (Boolean)

    controller actions to ignore when applying this filter

  • :only (Boolean)

    controller actions to apply this filter



191
192
193
194
195
196
197
# File 'lib/load_and_authorize_resource.rb', line 191

def authorize_resource(options={})
  options = options.dup
  unless options[:only] or options[:except]
    options.reverse_merge!(only: [:show, :new, :create, :edit, :update, :destroy])
  end
  before_action :authorize_resource, options
end

#load_and_authorize_parent(*names) ⇒ Object

A convenience method for calling both load_parent and authorize_parent



154
155
156
157
# File 'lib/load_and_authorize_resource.rb', line 154

def load_and_authorize_parent(*names)
  load_parent(*names)
  authorize_parent(*names)
end

#load_and_authorize_resource(options = {}) ⇒ Object

A convenience method for calling both load_resource and authorize_resource



200
201
202
203
# File 'lib/load_and_authorize_resource.rb', line 200

def load_and_authorize_resource(options={})
  load_resource(options)
  authorize_resource(options)
end

#load_parent(*names) ⇒ Object

Macro sets a before filter to load the parent resource. Pass in one symbol for each potential parent you're nested under.

For example, if you have routes:

resources :people do
  resources :notes
end

resources :groups do
  resources :notes
end

...you can call load_parent like so in your controller:

class NotesController < ApplicationController
  load_parent :person, :group
end

This will attempt to do the following for each resource, in order:

  1. look for params[:person_id]
  2. if present, call Person.find(params[:person_id])
  3. set @person

If we've exhausted our list of potential parent resources without seeing the needed parameter (:person_id or :group_id), then a ParameterMissing error is raised.

Note: load_parent assumes you've only nested your route a single layer deep, e.g. /parents/1/children/2 You're on your own if you want to load multiple nested parents, e.g. /grandfathers/1/parents/2/children/3

If you wish to also allow shallow routes (no parent), you can set the :shallow option to true:

class NotesController < ApplicationController
  load_parent :person, :group, shallow: true
end

The :shallow option is aliased to :optional in cases where it sense to think about parent resources that way. Further, you can call the macro more than once should you want to make some optional and some not:

class NotesController < ApplicationController
  load_parent :person, :group, optional: true
  load_parent :book
end

Additionally, a private method is defined with the same name as the resource. The method looks basically like this (if you were to write it yourself):

class NotesController < ApplicationController

  private

  def notes
    if @person
      @person.notes.all
    elsif not required(:person)
      Note.all
    end
  end
end

You can change the name of this accessor if it is not the same as the resource this controller represents:

class NotesController < ApplicationController
  load_parent :group, children: :people
end

This will create a private method called "people" that either returns @group.people.all or Person.all (only if @group is optional).

Parameters:

  • names (Array<String, Symbol>)

    one or more names of resources in lower case

  • options (Hash)

    a customizable set of options



115
116
117
118
119
120
121
# File 'lib/load_and_authorize_resource.rb', line 115

def load_parent(*names)
  options = names.extract_options!.dup
  required = !(options.delete(:shallow) || options.delete(:optional))
  save_nested_resource_options(:load, names, required: required)
  define_scope_method(names, options.delete(:children))
  before_action :load_parent, options
end

#load_resource(options = {}) ⇒ Object

Load the resource and set to an instance variable.

For example:

class NotesController < ApplicationController
  load_resource
end

...automatically finds the note for actions show, edit, update, and destroy.

For the new action, simply instantiates a new resource. For create, instantiates and sets attributes to <resource>_params.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :except (Boolean)

    controller actions to ignore when applying this filter

  • :only (Boolean)

    controller actions to apply this filter (default is show, new, create, edit, update, and destroy)

  • :children (String, Symbol)

    name of child accessor (inferred from controller name, e.g. "notes" for the NotesController)



175
176
177
178
179
180
181
182
# File 'lib/load_and_authorize_resource.rb', line 175

def load_resource(options={})
  options = options.dup
  unless options[:only] or options[:except]
    options.reverse_merge!(only: [:show, :new, :create, :edit, :update, :destroy])
  end
  define_scope_method([], options.delete(:children))
  before_action :load_resource, options
end

#resource_accessor_nameObject

Returns the name of the resource, in plural form, e.g. "notes"

By default, this is simply the controller_name.



217
218
219
# File 'lib/load_and_authorize_resource.rb', line 217

def resource_accessor_name
  controller_name
end

#resource_nameObject

Returns the name of the resource, in singular form, e.g. "note"

By default, this is simply controller_name.singularize.



209
210
211
# File 'lib/load_and_authorize_resource.rb', line 209

def resource_name
  controller_name.singularize
end