Module: Sinatra::RespondWith
- Defined in:
- lib/sinatra/respond_with.rb
Overview
Sinatra::RespondWith
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
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 to
to_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.
Defined Under Namespace
Modules: Helpers Classes: Format
Instance Attribute Summary collapse
-
#ext_map ⇒ Object
Returns the value of attribute ext_map.
Instance Method Summary collapse
- #mime_type ⇒ Object
- #remap_extensions ⇒ Object
- #rendering_method(engine) ⇒ Object
- #respond_to(*formats) ⇒ Object
Instance Attribute Details
#ext_map ⇒ Object
Returns the value of attribute ext_map.
187 188 189 |
# File 'lib/sinatra/respond_with.rb', line 187 def ext_map @ext_map end |
Instance Method Details
#mime_type ⇒ Object
196 197 198 199 200 |
# File 'lib/sinatra/respond_with.rb', line 196 def mime_type(*) result = super remap_extensions result end |
#remap_extensions ⇒ Object
189 190 191 192 193 194 |
# File 'lib/sinatra/respond_with.rb', line 189 def remap_extensions ext_map.clear Rack::Mime::MIME_TYPES.each { |e,t| ext_map[t] << e[1..-1].to_sym } ext_map['text/javascript'] << 'js' ext_map['text/xml'] << 'xml' end |
#rendering_method(engine) ⇒ Object
213 214 215 216 217 |
# File 'lib/sinatra/respond_with.rb', line 213 def rendering_method(engine) return [engine] if Sinatra::Templates.method_defined? engine return [:mab] if engine.to_sym == :markaby [:render, :engine] end |
#respond_to(*formats) ⇒ Object
202 203 204 205 206 207 208 209 210 211 |
# File 'lib/sinatra/respond_with.rb', line 202 def respond_to(*formats) if formats.any? @respond_to ||= [] @respond_to.concat formats elsif @respond_to.nil? and superclass.respond_to? :respond_to superclass.respond_to else @respond_to end end |