module Merb::Router::Resources

Public Instance Methods

resource(name, *args, &block) click to toggle source

Behavior#resource is a route helper for defining a singular RESTful resource. It yields to a block for child routes.

Parameters

name<String, Symbol>

The name of the resource.

options<Hash>

Overides and parameters to be associated with the route.

Options (options)

:namespace<~to_s>: The namespace for this route. :name_prefix<~to_s>:

A prefix for the named routes. If a namespace is passed and there
isn't a name prefix, the namespace will become the prefix.

:controller<~to_s>: The controller for this route

Block parameters

next_level<Behavior>

The child behavior.

Returns

Array

Routes which define a RESTful single resource.

Examples

r.resource :account # will result in the typical RESTful CRUD
  # shows new resource form      
  # GET     /account/new                :action => "new"

  # creates resource      
  # POST    /account/?(\.:format)?,     :action => "create"

  # shows resource      
  # GET     /account/(\.:format)?       :action => "show"

  # shows edit form      
  # GET     /account//edit           :action => "edit"

  # updates resource      
  # PUT     /account/(\.:format)?       :action => "update"

  # shows deletion confirmation page      
  # GET     /account//delete         :action => "delete"

  # destroys resources      
  # DELETE  /account/(\.:format)?       :action => "destroy"

You can optionally pass :namespace and :controller to refine the routing or pass a block to nest resources.

r.resource :account, :namespace => "admin" do |account|
  account.resources :preferences, :controller => "settings"
end

:api: public

# File lib/merb-core/dispatch/router/resources.rb, line 227
def resource(name, *args, &block)
  name    = name.to_s
  options = extract_options_from_args!(args) || {}
  params  = { :controller => options.delete(:controller) || name.pluralize }
  member  = { :new => :get, :edit => :get, :delete => :get }.merge(options.delete(:member) || {})

  options[:name_prefix]       ||= nil # Don't use a name_prefix if not needed
  options[:resource_prefix]   ||= nil # Don't use a resource_prefix if not needed
  options[:controller_prefix] ||= options.delete(:namespace)

  self.namespace(name, options).to(params) do |resource|
    # => show
    
    resource.match("(.:format)", :method => :get).to(:action => "show").
      name(name).register_resource(name)
      
    # => create
    resource.match("(.:format)", :method => :post).to(:action => "create")
      
    # => update
    resource.match("(.:format)", :method => :put).to(:action => "update")
      
    # => destroy
    resource.match("(.:format)", :method => :delete).to(:action => "destroy")
    
    member.each_pair do |action, method|
      action = action.to_s
      resource.match("/#{action}(.:format)", :method => method).to(:action => action).
        name(action, name).register_resource(name, action)
    end

    if block_given?
      builders = {}
      
      builders[:member] = lambda do |action, to, method|
        resource.match("/#{action}(.:format)", :method => method).to(:action => to).
          name(action, name).register_resource(name, action)
      end
      
      resource.options(:name_prefix => name, :resource_prefix => name).
        resource_block(builders, &block)
    end
  end
end
resources(name, *args, &block) click to toggle source

Behavior#resources is a route helper for defining a collection of RESTful resources. It yields to a block for child routes.

Parameters

name<String, Symbol>

The name of the resources

options<Hash>

Ovverides and parameters to be associated with the route

Options (options)

:namespace<~to_s>: The namespace for this route. :name_prefix<~to_s>:

A prefix for the named routes. If a namespace is passed and there
isn't a name prefix, the namespace will become the prefix.

:controller<~to_s>: The controller for this route :collection<~to_s>: Special settings for the collections routes :member<Hash>:

Special settings and resources related to a specific member of this
resource.

:identify<Symbol|Array>: The method(s) that should be called on the object

before inserting it into an URL.

:keys<Array>:

A list of the keys to be used instead of :id with the resource in the order of the url.

:singular<Symbol>

Block parameters

next_level<Behavior>

The child behavior.

Returns

Array

Routes which will define the specified RESTful collection of resources

Examples

r.resources :posts # will result in the typical RESTful CRUD
  # lists resources
  # GET     /posts/?(\.:format)?      :action => "index"
  # GET     /posts/index(\.:format)?  :action => "index"

  # shows new resource form
  # GET     /posts/new                :action => "new"

  # creates resource
  # POST    /posts/?(\.:format)?,     :action => "create"

  # shows resource
  # GET     /posts/:id(\.:format)?    :action => "show"

  # shows edit form
  # GET     /posts/:id/edit        :action => "edit"

  # updates resource
  # PUT     /posts/:id(\.:format)?    :action => "update"

  # shows deletion confirmation page
  # GET     /posts/:id/delete      :action => "delete"

  # destroys resources
  # DELETE  /posts/:id(\.:format)?    :action => "destroy"

# Nesting resources
r.resources :posts do |posts|
  posts.resources :comments
end

:api: public

# File lib/merb-core/dispatch/router/resources.rb, line 70
def resources(name, *args, &block)
  name       = name.to_s
  options    = extract_options_from_args!(args) || {}
  match_opts = options.except(*resource_options)
  options    = options.only(*resource_options)
  singular   = options[:singular] ? options[:singular].to_s : Extlib::Inflection.singularize(name)
  klass_name = args.first ? args.first.to_s : singular.to_const_string
  keys       = options.delete(:keys) || options.delete(:key)
  params     = { :controller => options.delete(:controller) || name }
  collection = options.delete(:collection) || {}
  member     = { :edit => :get, :delete => :get }.merge(options.delete(:member) || {})
  
  # Use the identifier for the class as a default
  begin
    if klass = Object.full_const_get(klass_name)
      keys ||= options[:identify]
      keys ||= @identifiers[klass]
    elsif options[:identify]
      raise Error, "The constant #{klass_name} does not exist, please specify the constant for this resource"
    end
  rescue NameError => e
    Merb.logger.debug!("Could not find resource model #{klass_name}")
  end
  
  keys = [ keys || :id ].flatten
  

  # Try pulling :namespace out of options for backwards compatibility
  options[:name_prefix]       ||= nil # Don't use a name_prefix if not needed
  options[:resource_prefix]   ||= nil # Don't use a resource_prefix if not needed
  options[:controller_prefix] ||= options.delete(:namespace)

  context = options[:identify]
  context = klass && options[:identify] ? identify(klass => options.delete(:identify)) : self
  context.namespace(name, options).to(params) do |resource|
    root_keys = keys.map { |k| ":#{k}" }.join("/")
    
    # => index
    resource.match("(/index)(.:format)", :method => :get).to(:action => "index").
      name(name).register_resource(name)
      
    # => create
    resource.match("(.:format)", :method => :post).to(:action => "create")
    
    # => new
    resource.match("/new(.:format)", :method => :get).to(:action => "new").
      name("new", singular).register_resource(name, "new")

    # => user defined collection routes
    collection.each_pair do |action, method|
      action = action.to_s
      resource.match("/#{action}(.:format)", :method => method).to(:action => "#{action}").
        name(action, name).register_resource(name, action)
    end

    if block_given?
      parent_keys = keys.map do |k|
        k == :id ? "#{singular}_id".to_sym : k
      end
      
      nested_keys = parent_keys.map { |k| ":#{k}" }.join("/")

      nested_match_opts = match_opts.except(:id)
      nested_match_opts["#{singular}_id".to_sym] = match_opts[:id] if match_opts[:id]
      
      # Procs for building the extra collection/member resource routes
      builders    = {}
      
      builders[:collection] = lambda do |action, to, method|
        resource.match("/#{action}(.:format)", match_opts.merge(:method => method)).
          to(:action => to).name(action, name).register_resource(name, action)
      end
      
      builders[:member] = lambda do |action, to, method|
        resource.match("/#{root_keys}/#{action}(.:format)", match_opts.merge(:method => method)).
          to(:action => to).name(action, singular).register_resource(klass_name, action, :identifiers => keys)
      end
      
      resource.options(:name_prefix => singular, :resource_prefix => klass_name, :parent_keys => parent_keys).
        match("/#{nested_keys}", nested_match_opts).resource_block(builders, &block)
    end

    # => show
    resource.match("/#{root_keys}(.:format)", match_opts.merge(:method => :get)).to(:action => "show").
      name(singular).register_resource(klass_name, :identifiers => keys)

    # => user defined member routes
    member.each_pair do |action, method|
      action = action.to_s
      resource.match("/#{root_keys}/#{action}(.:format)", match_opts.merge(:method => method)).
        to(:action => "#{action}").name(action, singular).register_resource(klass_name, action, :identifiers => keys)
    end

    # => update
    resource.match("/#{root_keys}(.:format)", match_opts.merge(:method => :put)).
      to(:action => "update")

    # => destroy
    resource.match("/#{root_keys}(.:format)", match_opts.merge(:method => :delete)).
      to(:action => "destroy")

  end # namespace
end

Protected Instance Methods

register_resource(*key) click to toggle source

:api: private

# File lib/merb-core/dispatch/router/resources.rb, line 275
def register_resource(*key)
  options     = extract_options_from_args!(key) || {}
  key         = [ @options[:resource_prefix], key ].flatten.compact
  identifiers = [ @options[:parent_keys], options[:identifiers] ]
  @route.resource = key
  @route.resource_identifiers = identifiers.flatten.compact.map { |id| id.to_sym }
  self
end
resource_block(builders, &block) click to toggle source

:api: private

# File lib/merb-core/dispatch/router/resources.rb, line 285
def resource_block(builders, &block)
  behavior = ResourceBehavior.new(builders, @proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
  with_behavior_context(behavior, &block)
end
resource_options() click to toggle source
# File lib/merb-core/dispatch/router/resources.rb, line 290
def resource_options
  [:singular, :keys, :key, :controller, :member, :collection, :identify,
    :name_prefix, :resource_prefix, :controller_prefix, :namespace, :path]
end