module InheritedResources::ClassMethods

def actions(*actions_to_keep)


actions :all, :except => :index
actions :index, :show, :edit

Syntax is borrowed from resource_controller.
Defines which actions will be inherited from the inherited controller.
def actions(*actions_to_keep)
  raise ArgumentError, 'Wrong number of arguments. You have to provide which actions you want to keep.' if actions_to_keep.empty?
  options = actions_to_keep.extract_options!
  actions_to_remove = Array(options[:except])
  actions_to_remove += ACTIONS - actions_to_keep.map { |a| a.to_sym } unless actions_to_keep.first == :all
  actions_to_remove.map! { |a| a.to_sym }.uniq!
  (instance_methods.map { |m| m.to_sym } & actions_to_remove).each do |action|
    undef_method action, "#{action}!"
  end
end

def acts_as_polymorphic! #:nodoc:

:nodoc:
def acts_as_polymorphic! #:nodoc:
  unless self.parents_symbols.include?(:polymorphic)
    include PolymorphicHelpers
    helper_method :parent_type, :parent_class
  end
end

def acts_as_shallow! #:nodoc:

:nodoc:
def acts_as_shallow! #:nodoc:
  include BelongsToHelpers
  include ShallowHelpers
end

def acts_as_singleton! #:nodoc:

:nodoc:
def acts_as_singleton! #:nodoc:
  unless self.resources_configuration[:self][:singleton]
    self.resources_configuration[:self][:singleton] = true
    include SingletonHelpers
    actions :all, except: :index
  end
end

def belongs_to(*symbols, &block)


type of polymorphic association)
* :optional - Tell the association is optional (it's a special

* :singleton - Tell it's a singleton association.

* :polymorphic - Tell the association is polymorphic.

You supply the collection name.

@company.admin_projects

But if you want to retrieve instead:

@company.projects

down the road:
which belongs to companies. This will do somewhere
suppose you have Tasks which belongs to Projects
* :collection_name - Tell how to retrieve the next collection. Let's

helper. By default is association name.
* :route_name - Allows you to specify what is the route name in your url

Default is :association_id, which in this case is :project_id.
* :param - Allows you to specify params key to retrieve the id.

Project.find(params[:project_id])

Instead of:

Project.find_by_title!(params[:project_id])

This will make your projects be instantiated as:

belongs_to :project, :finder => :find_by_title!

* :finder - Specifies which method should be called to instantiate the parent.

belongs_to :project, :instance_name => :my_project

* :instance_name - The instance variable name. By default is the name of the association.

give a string. Added for ActiveRecord belongs to compatibility.
* :class_name - Also allows you to specify the parent class, but you should

belongs_to :project, :parent_class => AdminProject

* :parent_class - Allows you to specify what is the parent class.

== Options

belongs_to :projects

Defines that this controller belongs to another resource.
def belongs_to(*symbols, &block)
  options = symbols.extract_options!
  options.symbolize_keys!
  options.assert_valid_keys(:class_name, :parent_class, :instance_name, :param,
                            :finder, :route_name, :collection_name, :singleton,
                            :polymorphic, :optional, :shallow)
  optional    = options.delete(:optional)
  shallow     = options.delete(:shallow)
  polymorphic = options.delete(:polymorphic)
  finder      = options.delete(:finder)
  if self.parents_symbols.empty?
    include BelongsToHelpers
    helper_method :parent, :parent?
  end
  acts_as_polymorphic! if polymorphic || optional
  acts_as_shallow!     if shallow
  raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty?
  raise ArgumentError, "You cannot define multiple associations with options: #{options.keys.inspect} to belongs to." unless symbols.size == 1 || options.empty?
  symbols.each do |symbol|
    symbol = symbol.to_sym
    if polymorphic || optional
      self.parents_symbols << :polymorphic unless self.parents_symbols.include?(:polymorphic)
      self.resources_configuration[:polymorphic][:symbols]   << symbol
      self.resources_configuration[:polymorphic][:optional] ||= optional
    else
      self.parents_symbols << symbol
    end
    self.resources_configuration[:self][:shallow] = true if shallow
    config = self.resources_configuration[symbol] = {}
    class_name = ''
    config[:parent_class] = options.delete(:parent_class) ||
      begin
        class_name = if options[:class_name]
          options.delete(:class_name)
        else
          namespace = self.name.deconstantize
          model_name = symbol.to_s.pluralize.classify
          klass = model_name
          while namespace != ''
            new_klass = "#{namespace}::#{model_name}"
            if new_klass.safe_constantize
              klass = new_klass
              break
            else
              namespace = namespace.deconstantize
            end
          end
          klass = model_name if klass.start_with?('::')
          klass
        end
        class_name.constantize
      rescue NameError => e
        raise unless e.message.include?(class_name)
        nil
      end
    config[:singleton]       = options.delete(:singleton) || false
    config[:collection_name] = options.delete(:collection_name) || symbol.to_s.pluralize.to_sym
    config[:instance_name]   = options.delete(:instance_name) || symbol
    config[:param]           = options.delete(:param) || :"#{symbol}_id"
    config[:route_name]      = options.delete(:route_name) || symbol
    config[:finder]          = finder || :find
  end
  if block
    class_eval(&block)
  else
    create_resources_url_helpers!
  end
end

def create_custom_action(resource_or_collection, action)

def create_custom_action(resource_or_collection, action)
  class_eval <<-CUSTOM_ACTION, __FILE__, __LINE__
    def #{action}(options={}, &block)
      respond_with(*with_chain(#{resource_or_collection}), options, &block)
    end
    alias :#{action}! :#{action}
    protected :#{action}!
  CUSTOM_ACTION
end

def custom_actions(options)


method is same as 'index' method. So you can override it if need
search_resources_{path,url} helpers. The body of generated 'search'
This macro creates 'search' method in controller and defines
custom_actions :collection => :search
* :collection - Allows you to specify collection actions.

method is same as 'show' method. So you can override it if need
delete_resource_{path,url} helpers. The body of generated 'delete'
This macro creates 'delete' method in controller and defines
custom_actions :resource => :delete
* :resource - Allows you to specify resource actions.

== Options

custom_actions :resource => [:delete, :transit], :collection => :search

Defines custom restful actions by resource or collection basis.
def custom_actions(options)
  self.resources_configuration[:self][:custom_actions] = options
  options.each do | resource_or_collection, actions |
    [*actions].each do | action |
      create_custom_action(resource_or_collection, action)
    end
  end
  create_resources_url_helpers!
  [*options[:resource]].each do | action |
    helper_method "#{action}_resource_path", "#{action}_resource_url"
  end
  [*options[:collection]].each do | action |
    helper_method "#{action}_resources_path", "#{action}_resources_url"
  end
end

def defaults(options)


defaults :finder => :find_by_slug

* :finder - Specifies which method should be called to instantiate the resource.

* :singleton - Tells if this controller is singleton or not.

controllers. Default to :admin on Admin::ProjectsController.
* :route_prefix - The route prefix which is automatically set in namespaced

* :route_instance_name - The name of the singular route. Defaults to :instance_name.

* :route_collection_name - The name of the collection route. Defaults to :collection_name.

:project in ProjectsController.
is set on all actions besides index action. Defaults to
* :instance_name - The name of the singular instance variable which

ProjectsController.
is set on the index action. Defaults to :projects in
* :collection_name - The name of the collection instance variable which

ProjectsController.
by the controller name. Defaults to Project in
* :resource_class - The resource class which by default is guessed

== Options

almost other methods depends on the values given to <>defaults.
this method is called, it should be on the top of your controller, since
Used to overwrite the default assumptions InheritedResources do. Whenever
def defaults(options)
  raise ArgumentError, 'Class method :defaults expects a hash of options.' unless options.is_a? Hash
  options.symbolize_keys!
  options.assert_valid_keys(:resource_class, :collection_name, :instance_name,
                            :class_name, :route_prefix, :route_collection_name,
                            :route_instance_name, :singleton, :finder)
  self.resource_class = options[:resource_class] if options.key?(:resource_class)
  self.resource_class = options[:class_name].constantize if options.key?(:class_name)
  acts_as_singleton! if options.delete(:singleton)
  config = self.resources_configuration[:self]
  if options.key?(:resource_class) or options.key?(:class_name)
    config[:request_name] = begin
      request_name = self.resource_class
      request_name = request_name.model_name.param_key if request_name.respond_to?(:model_name)
      request_name.to_s.underscore.tr('/', '_')
    end
    options.delete(:resource_class) and options.delete(:class_name)
  end
  options.each do |key, value|
    config[key] = value&.to_sym
  end
  create_resources_url_helpers!
end

def inherited(base) #:nodoc:

:nodoc:

Hook called on inheritance.
def inherited(base) #:nodoc:
  super(base)
  base.send :initialize_resources_class_accessors!
  base.send :create_resources_url_helpers!
end

def initialize_resources_class_accessors! #:nodoc:

:nodoc:

Initialize resources class accessors and set their default values.
def initialize_resources_class_accessors! #:nodoc:
  # First priority is the namespaced model, e.g. User::Group
  self.resource_class ||= begin
    namespaced_class = self.name.sub(/Controller$/, '').singularize
    namespaced_class.constantize
  rescue NameError
    nil
  end
  # Second priority is the top namespace model, e.g. EngineName::Article for EngineName::Admin::ArticlesController
  self.resource_class ||= begin
    namespaced_classes = self.name.sub(/Controller$/, '').split('::')
    namespaced_class = [namespaced_classes.first, namespaced_classes.last].join('::').singularize
    namespaced_class.constantize
  rescue NameError
    nil
  end
  # Third priority the camelcased c, i.e. UserGroup
  self.resource_class ||= begin
    camelcased_class = self.name.sub(/Controller$/, '').gsub('::', '').singularize
    camelcased_class.constantize
  rescue NameError
    nil
  end
  # Otherwise use the Group class, or fail
  self.resource_class ||= begin
    class_name = self.controller_name.classify
    class_name.constantize
  rescue NameError => e
    raise unless e.message.include?(class_name)
    nil
  end
  self.parents_symbols = self.parents_symbols.try(:dup) || []
  # Initialize resources configuration hash
  self.resources_configuration = self.resources_configuration.try(:dup) || {}
  self.resources_configuration.each do |key, value|
    next unless value.is_a?(Hash) || value.is_a?(Array)
    self.resources_configuration[key] = value.dup
  end
  config = (self.resources_configuration[:self] ||= {})
  config[:collection_name] = self.controller_name.to_sym
  config[:instance_name]   = self.controller_name.singularize.to_sym
  config[:route_collection_name] = config[:collection_name]
  config[:route_instance_name]   = config[:instance_name]
  # Deal with namespaced controllers
  namespaces = self.controller_path.split('/')[0..-2]
  # Remove namespace if its a mountable engine
  namespaces.delete_if do |namespace|
    begin
      "#{namespace}/engine".camelize.constantize.isolated?
    rescue StandardError, LoadError
      false
    end
  end
  config[:route_prefix] = namespaces.join('_').to_sym unless namespaces.empty?
  # Deal with default request parameters in namespaced controllers, e.g.
  # Forum::Thread#create will properly pick up the request parameter
  # which will be forum_thread, and not thread
  # Additionally make this work orthogonally with instance_name
  config[:request_name] = self.resource_class.to_s.underscore.tr('/', '_')
  # Initialize polymorphic, singleton, scopes and belongs_to parameters
  polymorphic = self.resources_configuration[:polymorphic] || { symbols: [], optional: false }
  polymorphic[:symbols] = polymorphic[:symbols].dup
  self.resources_configuration[:polymorphic] = polymorphic
end

def optional_belongs_to(*symbols, &block)


A quick method to declare optional belongs to.
def optional_belongs_to(*symbols, &block)
  options = symbols.extract_options!
  options[:optional] = true
  belongs_to(*symbols, options, &block)
end

def polymorphic_belongs_to(*symbols, &block)


A quick method to declare polymorphic belongs to.
def polymorphic_belongs_to(*symbols, &block)
  options = symbols.extract_options!
  options[:polymorphic] = true
  belongs_to(*symbols, options, &block)
end

def singleton_belongs_to(*symbols, &block)


A quick method to declare singleton belongs to.
def singleton_belongs_to(*symbols, &block)
  options = symbols.extract_options!
  options[:singleton] = true
  belongs_to(*symbols, options, &block)
end

def with_role(role)

Makes sense when using rails 3.1 mass assignment conventions
Defines the role to use when creating or updating resource.
def with_role(role)
  self.resources_configuration[:self][:role] = role.try(:to_sym)
end

def without_protection(flag)

def without_protection(flag)
  self.resources_configuration[:self][:without_protection] = flag
end