Module: Sinatra::RespondWith
Relationships & Source Files | |
Namespace Children | |
Modules:
| |
Classes:
| |
Defined in: | sinatra-contrib/lib/sinatra/respond_with.rb |
Overview
These extensions let ::Sinatra
automatically choose what template to render or
action to perform depending on the request's Accept header.
Example:
# Without Sinatra::RespondWith get '/' do data = { :name => 'example' } request.accept.each do |type| case type.to_s when 'text/html' halt haml(:index, :locals => data) when 'text/json' halt data.to_json when 'application/atom+xml' halt nokogiri(:'index.atom', :locals => data) when 'application/xml', 'text/xml' halt nokogiri(:'index.xml', :locals => data) when 'text/plain' halt 'just an example' end end error 406 end
# With Sinatra::RespondWith get '/' do respond_with :index, :name => 'example' do |f| f.txt { 'just an example' } end end
Both helper methods #respond_to and respond_with
let you define custom
handlers like the one above for text/plain
. respond_with
additionally
takes a template name and/or an object to offer the following default
behavior:
- If a template name is given, search for a template called
name.format.engine
(+index.xml.nokogiri+ in the above example). - If a template name is given, search for a templated called
name.engine
for engines known to result in the requested format (+index.haml+). - If a file extension associated with the mime type is known to
::Sinatra
, and the object responds toto_extension
, call that method and use the result (+data.to_json+).
Security
Since methods are triggered based on client input, this can lead to security issues (but not as severe as those might appear in the first place: keep in mind that only known file extensions are used). You should limit the possible formats you serve.
This is possible with the provides
condition:
get '/', :provides => [:html, :json, :xml, :atom] do respond_with :index, :name => 'example' end
However, since you have to set provides
for every route, this extension
adds an app global (class method) #respond_to, that lets you define content
types for all routes:
respond_to :html, :json, :xml, :atom get('/a') { respond_with :index, :name => 'a' } get('/b') { respond_with :index, :name => 'b' }
Custom Types
Use the on
method for defining actions for custom types:
get '/' do respond_to do |f| f.xml { nokogiri :index } f.on('application/custom') { custom_action } f.on('text/') { data.to_s } f.on('/*') { "matches everything" } end end
Definition order does not matter.
Class Method Summary
- .engines private
- .jrubyify(engs) private
- .registered(base) private
Instance Method Summary
Class Method Details
.engines (private)
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 250
def self.engines engines = { css: %i[sass scss], xml: %i[builder nokogiri], html: %i[erb erubi haml hamlit slim liquid mab markdown rdoc], all: (Sinatra::Templates.instance_methods.map(&:to_sym) + [:mab] - %i[find_template markaby]), json: [:yajl] } engines.default = [] defined?(JRUBY_VERSION) ? jrubyify(engines) : engines end
.jrubyify(engs) (private)
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 241
def self.jrubyify(engs) not_supported = [:markdown] engs.each_key do |key| engs[key].collect! { |eng| eng == :yajl ? :json_pure : eng } engs[key].delete_if { |eng| not_supported.include?(eng) } end engs end
.registered(base) (private)
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 264
def self.registered(base) base.set :ext_map, Hash.new { |h, k| h[k] = [] } base.set :template_engines, engines base.remap_extensions base.helpers Helpers end
Instance Method Details
#compile!(verb, path, block, **options) (private)
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 236
def compile!(verb, path, block, ** ) [:provides] ||= respond_to if respond_to super end
#mime_type
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 208
def mime_type(*) result = super remap_extensions result end
#remap_extensions
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 201
def remap_extensions ext_map.clear Rack::Mime::MIME_TYPES.each { |e, t| ext_map[t] << e[1..].to_sym } ext_map['text/javascript'] << 'js' ext_map['text/xml'] << 'xml' end
#rendering_method(engine)
[ GitHub ]#respond_to(*formats)
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/respond_with.rb', line 214
def respond_to(*formats) @respond_to ||= nil if formats.any? @respond_to ||= [] @respond_to.concat formats elsif @respond_to.nil? && superclass.respond_to?(:respond_to) superclass.respond_to else @respond_to end end