Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* Add pluggable JSON backends with support for the JSON gem. [rick]
    Example: ActiveSupport::JSON.backend = "JSONGem"

  All internal Rails JSON encoding is now handled by ActiveSupport::JSON.encode().  Use of #to_json is not recommended, as it may clash with other libraries that overwrite it.  However, you can recover Rails specific functionality
  if you really want to use #to_json.

    gem 'json'
    ActiveSupport::JSON.backend = "JSONGem"

    class ActiveRecord::Base
      alias to_json rails_to_json
    end
  • Loading branch information
technoweenie committed Apr 23, 2009
1 parent bab2bfa commit 3c4c6bd
Show file tree
Hide file tree
Showing 32 changed files with 384 additions and 239 deletions.
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/base/render.rb
Expand Up @@ -254,7 +254,7 @@ def render(options = nil, extra_options = {}, &block) #:doc:
render_for_text(js)

elsif json = options[:json]
json = json.to_json unless json.is_a?(String)
json = ActiveSupport::JSON.encode(json) unless json.is_a?(String)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
response.content_type ||= Mime::JSON
render_for_text(json)
Expand Down
16 changes: 9 additions & 7 deletions actionpack/lib/action_view/helpers/prototype_helper.rb
Expand Up @@ -973,7 +973,7 @@ def drop_receiving(id, options = {})
def loop_on_multiple_args(method, ids)
record(ids.size>1 ?
"#{javascript_object_for(ids)}.each(#{method})" :
"#{method}(#{ids.first.to_json})")
"#{method}(#{ActiveSupport::JSON.encode(ids.first)})")
end

def page
Expand All @@ -997,7 +997,7 @@ def render(*options_for_render)
end

def javascript_object_for(object)
object.respond_to?(:to_json) ? object.to_json : object.inspect
ActiveSupport::JSON.encode(object)
end

def arguments_for_call(arguments, block = nil)
Expand Down Expand Up @@ -1139,7 +1139,7 @@ def append_to_function_chain!(call)
class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
def initialize(generator, id)
@id = id
super(generator, "$(#{id.to_json})")
super(generator, "$(#{ActiveSupport::JSON.encode(id)})")
end

# Allows access of element attributes through +attribute+. Examples:
Expand Down Expand Up @@ -1184,10 +1184,12 @@ def respond_to?(method)
true
end

def to_json(options = nil)
def rails_to_json(options = nil)
@variable
end

alias to_json rails_to_json

private
def append_to_function_chain!(call)
@generator << @variable if @empty
Expand All @@ -1211,7 +1213,7 @@ def each_slice(variable, number, &block)
enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block
else
add_variable_assignment!(variable)
append_enumerable_function!("eachSlice(#{number.to_json});")
append_enumerable_function!("eachSlice(#{ActiveSupport::JSON.encode(number)});")
end
end

Expand All @@ -1232,7 +1234,7 @@ def inject(variable, memo, &block)

def pluck(variable, property)
add_variable_assignment!(variable)
append_enumerable_function!("pluck(#{property.to_json});")
append_enumerable_function!("pluck(#{ActiveSupport::JSON.encode(property)});")
end

def zip(variable, *arguments, &block)
Expand Down Expand Up @@ -1296,7 +1298,7 @@ def append_enumerable_function!(call)

class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
def initialize(generator, pattern)
super(generator, "$$(#{pattern.to_json})")
super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})")
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions actionpack/lib/action_view/helpers/scriptaculous_helper.rb
Expand Up @@ -43,7 +43,7 @@ module ScriptaculousHelper
# You can change the behaviour with various options, see
# http://script.aculo.us for more documentation.
def visual_effect(name, element_id = false, js_options = {})
element = element_id ? element_id.to_json : "element"
element = element_id ? ActiveSupport::JSON.encode(element_id) : "element"

js_options[:queue] = if js_options[:queue].is_a?(Hash)
'{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
Expand Down Expand Up @@ -138,7 +138,7 @@ def sortable_element(element_id, options = {})
end

def sortable_element_js(element_id, options = {}) #:nodoc:
options[:with] ||= "Sortable.serialize(#{element_id.to_json})"
options[:with] ||= "Sortable.serialize(#{ActiveSupport::JSON.encode(element_id)})"
options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }

Expand All @@ -149,7 +149,7 @@ def sortable_element_js(element_id, options = {}) #:nodoc:
options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment]
options[:only] = array_or_string_for_javascript(options[:only]) if options[:only]

%(Sortable.create(#{element_id.to_json}, #{options_for_javascript(options)});)
%(Sortable.create(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});)
end

# Makes the element with the DOM ID specified by +element_id+ draggable.
Expand All @@ -164,7 +164,7 @@ def draggable_element(element_id, options = {})
end

def draggable_element_js(element_id, options = {}) #:nodoc:
%(new Draggable(#{element_id.to_json}, #{options_for_javascript(options)});)
%(new Draggable(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});)
end

# Makes the element with the DOM ID specified by +element_id+ receive
Expand Down Expand Up @@ -219,7 +219,7 @@ def drop_receiving_element_js(element_id, options = {}) #:nodoc:
# Confirmation happens during the onDrop callback, so it can be removed from the options
options.delete(:confirm) if options[:confirm]

%(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});)
%(Droppables.add(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});)
end
end
end
Expand Down
18 changes: 9 additions & 9 deletions actionpack/test/controller/render_test.rb
Expand Up @@ -194,19 +194,19 @@ def accessing_controller_name_in_template
end

def render_json_hello_world
render :json => {:hello => 'world'}.to_json
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end

def render_json_hello_world_with_callback
render :json => {:hello => 'world'}.to_json, :callback => 'alert'
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
end

def render_json_with_custom_content_type
render :json => {:hello => 'world'}.to_json, :content_type => 'text/javascript'
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript'
end

def render_symbol_json
render :json => {:hello => 'world'}.to_json
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end

def render_json_with_render_to_string
Expand Down Expand Up @@ -875,31 +875,31 @@ def test_render_file_from_template

def test_render_json
get :render_json_hello_world
assert_equal '{"hello": "world"}', @response.body
assert_equal '{"hello":"world"}', @response.body
assert_equal 'application/json', @response.content_type
end

def test_render_json_with_callback
get :render_json_hello_world_with_callback
assert_equal 'alert({"hello": "world"})', @response.body
assert_equal 'alert({"hello":"world"})', @response.body
assert_equal 'application/json', @response.content_type
end

def test_render_json_with_custom_content_type
get :render_json_with_custom_content_type
assert_equal '{"hello": "world"}', @response.body
assert_equal '{"hello":"world"}', @response.body
assert_equal 'text/javascript', @response.content_type
end

def test_render_symbol_json
get :render_symbol_json
assert_equal '{"hello": "world"}', @response.body
assert_equal '{"hello":"world"}', @response.body
assert_equal 'application/json', @response.content_type
end

def test_render_json_with_render_to_string
get :render_json_with_render_to_string
assert_equal '{"hello": "partial html"}', @response.body
assert_equal '{"hello":"partial html"}', @response.body
assert_equal 'application/json', @response.content_type
end

Expand Down
16 changes: 8 additions & 8 deletions actionpack/test/template/prototype_helper_test.rb
Expand Up @@ -328,28 +328,28 @@ def test_replace_element_with_string
def test_remove
assert_equal 'Element.remove("foo");',
@generator.remove('foo')
assert_equal '["foo", "bar", "baz"].each(Element.remove);',
assert_equal '["foo","bar","baz"].each(Element.remove);',
@generator.remove('foo', 'bar', 'baz')
end

def test_show
assert_equal 'Element.show("foo");',
@generator.show('foo')
assert_equal '["foo", "bar", "baz"].each(Element.show);',
assert_equal '["foo","bar","baz"].each(Element.show);',
@generator.show('foo', 'bar', 'baz')
end

def test_hide
assert_equal 'Element.hide("foo");',
@generator.hide('foo')
assert_equal '["foo", "bar", "baz"].each(Element.hide);',
assert_equal '["foo","bar","baz"].each(Element.hide);',
@generator.hide('foo', 'bar', 'baz')
end

def test_toggle
assert_equal 'Element.toggle("foo");',
@generator.toggle('foo')
assert_equal '["foo", "bar", "baz"].each(Element.toggle);',
assert_equal '["foo","bar","baz"].each(Element.toggle);',
@generator.toggle('foo', 'bar', 'baz')
end

Expand Down Expand Up @@ -386,7 +386,7 @@ def test_to_s
assert_equal <<-EOS.chomp, @generator.to_s
Element.insert("element", { top: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" });
Element.insert("element", { bottom: "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E" });
["foo", "bar"].each(Element.remove);
["foo","bar"].each(Element.remove);
Element.update("baz", "\\u003Cp\\u003EThis is a test\\u003C/p\\u003E");
EOS
end
Expand Down Expand Up @@ -555,8 +555,8 @@ def test_collection_proxy_with_zip
end

assert_equal <<-EOS.strip, @generator.to_s
var a = [1, 2, 3].zip([4, 5, 6], [7, 8, 9]);
var b = [1, 2, 3].zip([4, 5, 6], [7, 8, 9], function(array) {
var a = [1, 2, 3].zip([4,5,6], [7,8,9]);
var b = [1, 2, 3].zip([4,5,6], [7,8,9], function(array) {
return array.reverse();
});
EOS
Expand Down Expand Up @@ -607,7 +607,7 @@ def test_debug_rjs

def test_literal
literal = @generator.literal("function() {}")
assert_equal "function() {}", literal.to_json
assert_equal "function() {}", ActiveSupport::JSON.encode(literal)
assert_equal "", @generator.to_s
end

Expand Down
10 changes: 7 additions & 3 deletions activerecord/lib/active_record/serializers/json_serializer.rb
Expand Up @@ -74,21 +74,25 @@ def self.included(base)
# {"comments": [{"body": "Don't think too hard"}],
# "title": "So I was thinking"}]}
def to_json(options = {})
json = JsonSerializer.new(self, options).to_s
if include_root_in_json
"{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
"{#{self.class.json_class_name}:#{json}}"
else
JsonSerializer.new(self, options).to_s
json
end
end

# For compatibility with ActiveSupport::JSON.encode
alias rails_to_json to_json

def from_json(json)
self.attributes = ActiveSupport::JSON.decode(json)
self
end

class JsonSerializer < ActiveRecord::Serialization::Serializer #:nodoc:
def serialize
serializable_record.to_json
ActiveSupport::JSON.encode(serializable_record)
end
end

Expand Down

0 comments on commit 3c4c6bd

Please sign in to comment.