module Sinatra::API::Resources

API for defining parameters an endpoint requires or accepts, their types, and optional validators.

Public Class Methods

included(app) click to toggle source
# File lib/sinatra/api/resources.rb, line 28
def self.included(app)
  app.set(:requires) do |*resources|
    condition do
      @required = resources.collect { |r| r.to_s }
      @required.each do |r|
        @parent_resource = api_locate_resource(r, @parent_resource)
      end
    end
  end

  Sinatra::API.on :request do |instance|
    @parent_resource = nil
  end
end

Private Instance Methods

api_locate_resource(r, container = nil) click to toggle source

Attempt to locate a resource based on an ID supplied in a request parameter.

If the param map contains a resource id (ie, :folder_id), we attempt to locate and expose it to the route.

A 404 is raised if:

1. the scope is missing
2. the resource couldn't be found in its scope

If the resources were located, they’re accessible using @folder or @page.

The route can be halted using the :requires => [] condition when it expects a resource.

@example using :requires to reject a request with an invalid @page

get '/folders/:folder_id/pages/:page_id', :requires => [ :page ] do
  @page.show    # page is good
  @folder.show  # so is its folder
end
# File lib/sinatra/api/resources.rb, line 67
def api_locate_resource(r, container = nil)
  resource_id = params[r + '_id'].to_i
  rklass      = r.camelize

  collection = case
  when container.nil?;  eval "#{ResourcePrefix}#{rklass}"
  else;                 container.send("#{r.to_plural}")
  end

  Sinatra::API.logger.debug "locating resource #{r} with id #{resource_id} " +
    "from #{collection} [#{container}]"

  resource = collection.get(resource_id)

  if !resource
    m = "No such resource: #{rklass}##{resource_id}"
    if container
      m << " in #{container.class.name.to_s}##{container.id}"
    end

    halt 404, m
  end

  if respond_to?(:can?)
    unless can? :access, resource
      halt 403, "You do not have access to this #{rklass} resource."
    end
  end

  instance_variable_set('@'+r, resource)

  Sinatra::API.trigger :resource_located, resource, r

  resource
end