In Files

Class/Module Index [+]

Quicksearch

Camping::Controllers

Public Class Methods

REST(r, options = {}) click to toggle source

Calling REST "<resource name>" creates a controller with the appropriate routes and maps your REST methods to standard Camping controller mehods. This is meant to be used in your Controllers module in place of R <routes>.

Your REST class should define the following methods:

  • create

  • read(id)

  • update(id)

  • destroy(id)

  • list

Routes will be automatically created based on the resource name fed to the REST method. Your class must have the same (but CamelCaps'ed) name as the resource name. So if your resource name is 'kittens', your controller class must be Kittens.

For example:

module Foobar::Controllers
  class Kittens < REST 'kittens'
    # POST /kittens
    def create
    end

    # GET /kittens/(\d+)
    def read(id)
    end

    # PUT /kittens/(\d+)
    def update(id)
    end

    # DELETE /kittens/(\d+)
    def destroy(id)
    end

    # GET /kittens
    def list
    end
  end
end

Custom actions are also possible. For example, to implement a 'meow' action simply add a 'meow' method to the above controller:

# POST/GET/PUT/DELETE /kittens/meow
# POST/GET/PUT/DELETE /kittens/(\d+)/meow
def meow(id)
end

Note that a custom action will respond to all four HTTP methods (POST/GET/PUT/DELETE).

Optionally, you can specify a :prefix key that will prepend the given string to the routes. For example, the following will create all of the above routes, prefixed with "/pets" (i.e. POST '/pets/kittens', GET '/pets/kittens/(\d+)', etc.):

module Foobar::Controllers
  class Items < REST 'kittens', :prefix => '/pets'
    # ...
  end
end

Format-based routing similar to that in ActiveResource is also implemented. For example, to get a list of kittens in XML format, place a GET call to /kittens.xml. See the documentation for the render() method for more info.

# File lib/reststop.rb, line 300
def REST(r, options = {})
  crud = R "#{options[:prefix]}/#{r}/([0-9a-zA-Z]+)/([a-z_]+)(?:\.[a-z]+)?",
    "#{options[:prefix]}/#{r}/([0-9a-zA-Z]+)(?:\.[a-z]+)?",
    "#{options[:prefix]}/#{r}/([a-z_]+)(?:\.[a-z]+)?",
    "#{options[:prefix]}/#{r}(?:\.[a-z]+)?"
    
  crud.module_eval do
    meta_def(:restful?){true}
    
    $LOG.debug("Creating RESTful controller for #{r.inspect} using Reststop #{::Reststop::VERSION::STRING}") if $LOG
    
    def get(id_or_custom_action = nil, custom_action =  nil) # :nodoc:
      id = @input[:id] if @input[:id]
      
      custom_action = @input[:action] if @input[:action]
      
      if self.methods.include? id_or_custom_action
        custom_action ||= id_or_custom_action
        id ||= nil
      else
        id ||= id_or_custom_action
      end
      
      id = id.to_i if id && id =~ /^[0-9]+$/
      
      @format = Controllers.read_format(@input, @env)
      
      begin
        if id.nil? && @input[:id].nil?
          custom_action ? send(custom_action) : list
        else
          custom_action ? send(custom_action, id || @input[:id]) : read(id || @input[:id])
        end
      rescue NoMethodError => e
        # FIXME: this is probably not a good way to do this, but we need to somehow differentiate
        #        between 'no such route' vs. other NoMethodErrors
        if e.message =~ /no such method/
          return no_method(e)
        else
          raise e
        end
      rescue ActiveRecord::RecordNotFound => e
        return not_found(e)
      end
    end
    
    
    def post(custom_action = nil) # :nodoc:
      @format = Controllers.read_format(@input, @env)
      custom_action ? send(custom_action) : create
    end
    
    
    def put(id, custom_action = nil) # :nodoc:
      id = id.to_i if id =~ /^[0-9]+$/
      @format = Controllers.read_format(@input, @env)
      custom_action ? send(custom_action, id || @input[:id]) : update(id || @input[:id])
    end
    
    
    def delete(id, custom_action = nil) # :nodoc:
      id = id.to_i if id =~ /^[0-9]+$/
      @format = Controllers.read_format(@input, @env)
      custom_action ? send(custom_action, id || @input[:id]) : destroy(id || @input[:id])
    end
    
    private
    def _error(message, status_code = 500, e = nil)
      @status = status_code
      @message = message
      begin
        render "error_#{status_code}".intern
      rescue NoMethodError
        if @format.to_s == 'XML'
          "<error code='#{status_code}'>#{@message}</error>"
        else
          out  = "<strong>#{@message}</strong>"
          out += "<pre style='color: #bbb'><strong>#{e.class}: #{e}</strong>\n#{e.backtrace.join("\n")}</pre>" if e
          out
        end
      end
    end
    
    def no_method(e)
      _error("No controller method responds to this route!", 501, e)
    end
    
    def not_found(e)
      _error("Record not found!", 404, e)
    end
  end
  crud
end
_error(message, status_code = 500, e = nil) click to toggle source
# File lib/reststop.rb, line 367
def _error(message, status_code = 500, e = nil)
  @status = status_code
  @message = message
  begin
    render "error_#{status_code}".intern
  rescue NoMethodError
    if @format.to_s == 'XML'
      "<error code='#{status_code}'>#{@message}</error>"
    else
      out  = "<strong>#{@message}</strong>"
      out += "<pre style='color: #bbb'><strong>#{e.class}: #{e}</strong>\n#{e.backtrace.join("\n")}</pre>" if e
      out
    end
  end
end
no_method(e) click to toggle source
# File lib/reststop.rb, line 383
def no_method(e)
  _error("No controller method responds to this route!", 501, e)
end
not_found(e) click to toggle source
# File lib/reststop.rb, line 387
def not_found(e)
  _error("Record not found!", 404, e)
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.