From 42596543dc0bac7aad9763b82ee4cc2b17f3110c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 6 Dec 2006 22:27:08 +0000 Subject: [PATCH] respond_to recognizes JSON. render :json => @person.to_json automatically sets the content type and takes a :callback option to specify a client-side function to call using the rendered JSON as an argument. References #4185. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5694 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 6 ++++ actionpack/lib/action_controller/base.rb | 32 +++++++++++++++++++ .../lib/action_controller/mime_types.rb | 1 + actionpack/lib/action_controller/request.rb | 2 ++ .../test/controller/mime_responds_test.rb | 20 ++++++++++++ actionpack/test/controller/render_test.rb | 18 +++++++++++ 6 files changed, 79 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 87fe235477..52253a8777 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,11 @@ *SVN* +* respond_to recognizes JSON. render :json => @person.to_json automatically sets the content type and takes a :callback option to specify a client-side function to call using the rendered JSON as an argument. #4185 [Scott Raymond, eventualbuddha] + # text/x-json response with body 'Element.show({:name: "David"})' + respond_to do |format| + format.json { render :json => { :name => "David" }.to_json, :callback => 'Element.show' } + end + * Makes :discard_year work without breaking multi-attribute parsing in AR. #1260, #3800 [sean@ardismg.com, jmartin@desertflood.com, stephen@touset.org, Bob Silva] * Adds html id attribute to date helper elements. #1050, #1382 [mortonda@dgrmm.net, David North, Bob Silva] diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 31016a47c5..cbf34e9742 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -650,6 +650,20 @@ module ActionController #:nodoc: # # _Deprecation_ _notice_: This used to have the signature render_text("text", status = 200) # + # === Rendering JSON + # + # Rendering JSON sets the content type to text/x-json and optionally wraps the JSON in a callback. It is expected + # that the response will be eval'd for use as a data structure. + # + # # Renders '{name: "David"}' + # render :json => {:name => "David"}.to_json + # + # Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag), + # so the callback option is provided for these cases. + # + # # Renders 'show({name: "David"})' + # render :json => {:name => "David"}.to_json, :callback => 'show' + # # === Rendering an inline template # # Rendering of an inline template works as a cross between text and action rendering where the source for the template @@ -733,6 +747,12 @@ module ActionController #:nodoc: elsif xml = options[:xml] render_xml(xml, options[:status]) + + elsif json = options[:json] + render_json(json, options[:callback], options[:status]) + + elsif yaml = options[:yaml] + render_yaml(yaml, options[:status]) elsif partial = options[:partial] partial = default_template_name if partial == true @@ -813,6 +833,18 @@ module ActionController #:nodoc: response.content_type = Mime::XML render_text(xml, status) end + + def render_json(json, callback = nil, status = nil) #:nodoc: + json = "#{callback}(#{json})" unless callback.blank? + + response.content_type = Mime::JSON + render_text(json, status) + end + + def render_yaml(yaml, status = nil) #:nodoc: + response.content_type = Mime::YAML + render_text(yaml, status) + end def render_nothing(status = nil) #:nodoc: render_text(' ', status) diff --git a/actionpack/lib/action_controller/mime_types.rb b/actionpack/lib/action_controller/mime_types.rb index d968344b26..4b6a00da1d 100644 --- a/actionpack/lib/action_controller/mime_types.rb +++ b/actionpack/lib/action_controller/mime_types.rb @@ -2,6 +2,7 @@ Mime::Type.register "*/*", :all Mime::Type.register "text/plain", :text Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml ) Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript ) +Mime::Type.register "text/x-json", :json, %w( application/x-json ) Mime::Type.register "text/calendar", :ics Mime::Type.register "text/csv", :csv Mime::Type.register "application/xml", :xml, %w( text/xml application/x-xml ) diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index 8c21adb8df..cff8522a02 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -66,6 +66,8 @@ module ActionController content_type = 'application/x-yaml' when 'xml' content_type = 'application/xml' + when 'json' + content_type = 'application/x-json' end end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 1d7fdc0052..8f1c56710f 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -19,6 +19,13 @@ class RespondToController < ActionController::Base type.all { render :text => "Nothing" } end end + + def json_or_yaml + respond_to do |type| + type.json { render :text => "JSON" } + type.yaml { render :yaml => "YAML" } + end + end def html_or_xml respond_to do |type| @@ -163,6 +170,19 @@ class MimeControllerTest < Test::Unit::TestCase get :just_xml assert_response 406 end + + def test_json_or_yaml + get :json_or_yaml + assert_equal 'JSON', @response.body + + @request.env["HTTP_ACCEPT"] = "text/yaml" + get :json_or_yaml + assert_equal 'YAML', @response.body + + @request.env["HTTP_ACCEPT"] = "text/x-json" + get :json_or_yaml + assert_equal 'JSON', @response.body + end def test_js_or_anything @request.env["HTTP_ACCEPT"] = "text/javascript, */*" diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 66429662e6..3cff829f8a 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -38,6 +38,14 @@ class TestController < ActionController::Base def render_text_hello_world render_text "hello world" end + + def render_json_hello_world + render_json({:hello => 'world'}.to_json) + end + + def render_json_hello_world_with_callback + render_json({:hello => 'world'}.to_json, 'alert') + end def render_custom_code render_text "hello world", "404 Moved" @@ -163,6 +171,16 @@ class RenderTest < Test::Unit::TestCase get :render_text_hello_world assert_equal "hello world", @response.body end + + def test_do_with_render_json + get :render_json_hello_world + assert_equal '{hello: "world"}', @response.body + end + + def test_do_with_render_json_with_callback + get :render_json_hello_world_with_callback + assert_equal 'alert({hello: "world"})', @response.body + end def test_do_with_render_custom_code get :render_custom_code