原创作者: hideto
阅读:1204次
评论:0条
更新时间:2011-05-26
Rails从HTTP Accept header得到客户端需要的response format信息
默认的MIME types见mime_type.rb:
我们可以在environment.rb里注册自己的MIME type:
看看源码mime_responds.rb:
我们看到,respond_to方法调用responder.send(type),如format.js,但是Responder类没有js方法,所以调用了method_missing方法
method_missing调用了custom方法,custom则eval了response.content_type的设置,然后block.call
最后调用responder.respond,@responses[priority].call调用了content_type的设置以及参数给的block
默认的MIME types见mime_type.rb:
ALL = Type.new "*/*", :all TEXT = Type.new "text/plain", :text HTML = Type.new "text/html", :html, %w( application/xhtml+xml ) JS = Type.new "text/javascript", :js, %w( application/javascript application/x-javascript ) ICS = Type.new "text/calendar", :ics CSV = Type.new "text/csv", :csv XML = Type.new "application/xml", :xml, %w( text/xml application/x-xml ) RSS = Type.new "application/rss+xml", :rss ATOM = Type.new "application/atom+xml", :atom YAML = Type.new "application/x-yaml", :yaml, %w( text/yaml ) JSON = Type.new "application/json", :json, %w( text/x-json ) SET = [ ALL, TEXT, HTML, JS, ICS, XML, RSS, ATOM, YAML, JSON ] def register(string, symbol, synonyms = []) Mime.send :const_set, symbol.to_s.upcase, Type.new(string, symbol, synonyms) SET << Mime.send(:const_get, symbol.to_s.upcase) LOOKUP[string] = EXTENSION_LOOKUP[symbol.to_s] = SET.last end
我们可以在environment.rb里注册自己的MIME type:
Mime::Type.register "image/jpg", :jpg
看看源码mime_responds.rb:
module ActionController module MimeResponds def self.included(base) base.send(:include, ActionController::MimeResponds::InstanceMethods) end module InstanceMethods def respond_to(*types, &block) raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block block ||= lambda { |responder| types.each { |type| responder.send(type) } } responder = Responder.new(block.binding) block.call(responder) responder.respond end end class Responder def initialize(block_binding) @block_binding = block_binding @mime_type_priority = eval( "(params[:format] && Mime::EXTENSION_LOOKUP[params[:format]]) ? " + "[ Mime::EXTENSION_LOOKUP[params[:format]] ] : request.accepts", block_binding ) @order = [] @responses = {} end def custom(mime_type, &block) mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s) @order << mime_type if block_given? @responses[mime_type] = Proc.new do eval "response.content_type = '#{mime_type.to_s}'", @block_binding block.call end else if source = DEFAULT_BLOCKS[mime_type.to_sym] @responses[mime_type] = eval(source, @block_binding) else raise ActionController::RenderError, "Expected a block but none was given for custom mime handler #{mime_type}" end end end def method_missing(symbol, &block) mime_constant = symbol.to_s.upcase if Mime::SET.include?(Mime.const_get(mime_constant)) custom(Mime.const_get(mime_constant), &block) else super end end def respond for priority in @mime_type_priority if priority == Mime::ALL @responses[@order.first].call return else if priority === @order @responses[priority].call return end end end if @order.include?(Mime::ALL) @responses[Mime::ALL].call else eval 'render(:nothing => true, :status => "406 Not Acceptable")', @block_binding end end end end end
我们看到,respond_to方法调用responder.send(type),如format.js,但是Responder类没有js方法,所以调用了method_missing方法
method_missing调用了custom方法,custom则eval了response.content_type的设置,然后block.call
最后调用responder.respond,@responses[priority].call调用了content_type的设置以及参数给的block
评论 共 0 条 请登录后发表评论