2017-07-09 13:41:28 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2011-06-06 14:17:44 -04:00
|
|
|
require "cases/helper"
|
2016-08-06 12:26:20 -04:00
|
|
|
require "models/contact"
|
|
|
|
require "models/post"
|
|
|
|
require "models/author"
|
|
|
|
require "models/tagging"
|
|
|
|
require "models/tag"
|
|
|
|
require "models/comment"
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2013-03-04 15:12:18 -05:00
|
|
|
module JsonSerializationHelpers
|
|
|
|
private
|
2016-08-06 13:55:02 -04:00
|
|
|
def set_include_root_in_json(value)
|
|
|
|
original_root_in_json = ActiveRecord::Base.include_root_in_json
|
|
|
|
ActiveRecord::Base.include_root_in_json = value
|
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
ActiveRecord::Base.include_root_in_json = original_root_in_json
|
|
|
|
end
|
2013-03-04 15:12:18 -05:00
|
|
|
end
|
|
|
|
|
2008-01-21 12:20:51 -05:00
|
|
|
class JsonSerializationTest < ActiveRecord::TestCase
|
2013-03-04 15:12:18 -05:00
|
|
|
include JsonSerializationHelpers
|
|
|
|
|
2008-04-01 16:09:45 -04:00
|
|
|
class NamespacedContact < Contact
|
2019-04-08 07:10:15 -04:00
|
|
|
column :name, "string"
|
2008-04-01 16:09:45 -04:00
|
|
|
end
|
|
|
|
|
2007-09-28 17:11:14 -04:00
|
|
|
def setup
|
|
|
|
@contact = Contact.new(
|
2016-08-06 13:37:57 -04:00
|
|
|
name: "Konata Izumi",
|
|
|
|
age: 16,
|
|
|
|
avatar: "binarydata",
|
|
|
|
created_at: Time.utc(2006, 8, 1),
|
|
|
|
awesome: true,
|
|
|
|
preferences: { shows: "anime" }
|
2007-09-28 17:11:14 -04:00
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2008-04-01 16:09:45 -04:00
|
|
|
def test_should_demodulize_root_in_json
|
2013-03-04 15:12:18 -05:00
|
|
|
set_include_root_in_json(true) do
|
2016-08-06 12:26:20 -04:00
|
|
|
@contact = NamespacedContact.new name: "whatever"
|
2013-03-04 15:12:18 -05:00
|
|
|
json = @contact.to_json
|
|
|
|
assert_match %r{^\{"namespaced_contact":\{}, json
|
|
|
|
end
|
2008-04-01 16:09:45 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_should_include_root_in_json
|
2013-03-04 15:12:18 -05:00
|
|
|
set_include_root_in_json(true) do
|
|
|
|
json = @contact.to_json
|
|
|
|
|
|
|
|
assert_match %r{^\{"contact":\{}, json
|
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_match %r{"age":16}, json
|
2016-09-16 12:44:05 -04:00
|
|
|
assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})
|
2013-03-04 15:12:18 -05:00
|
|
|
assert_match %r{"awesome":true}, json
|
|
|
|
assert_match %r{"preferences":\{"shows":"anime"\}}, json
|
|
|
|
end
|
2008-04-01 16:09:45 -04:00
|
|
|
end
|
|
|
|
|
2007-09-28 17:11:14 -04:00
|
|
|
def test_should_encode_all_encodable_attributes
|
|
|
|
json = @contact.to_json
|
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_match %r{"age":16}, json
|
2016-09-16 12:44:05 -04:00
|
|
|
assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"awesome":true}, json
|
|
|
|
assert_match %r{"preferences":\{"shows":"anime"\}}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_should_allow_attribute_filtering_with_only
|
2016-08-06 13:37:57 -04:00
|
|
|
json = @contact.to_json(only: [:name, :age])
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_match %r{"age":16}, json
|
|
|
|
assert_no_match %r{"awesome":true}, json
|
2016-09-16 12:44:05 -04:00
|
|
|
assert_not_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_no_match %r{"preferences":\{"shows":"anime"\}}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_should_allow_attribute_filtering_with_except
|
2016-08-06 13:37:57 -04:00
|
|
|
json = @contact.to_json(except: [:name, :age])
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_no_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_no_match %r{"age":16}, json
|
|
|
|
assert_match %r{"awesome":true}, json
|
2016-09-16 12:44:05 -04:00
|
|
|
assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"preferences":\{"shows":"anime"\}}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_methods_are_called_on_object
|
|
|
|
# Define methods on fixture.
|
|
|
|
def @contact.label; "Has cheezburger"; end
|
|
|
|
def @contact.favorite_quote; "Constraints are liberating"; end
|
|
|
|
|
|
|
|
# Single method.
|
2016-08-06 13:37:57 -04:00
|
|
|
assert_match %r{"label":"Has cheezburger"}, @contact.to_json(only: :name, methods: :label)
|
2007-09-28 17:11:14 -04:00
|
|
|
|
|
|
|
# Both methods.
|
2016-08-06 13:37:57 -04:00
|
|
|
methods_json = @contact.to_json(only: :name, methods: [:label, :favorite_quote])
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"label":"Has cheezburger"}, methods_json
|
|
|
|
assert_match %r{"favorite_quote":"Constraints are liberating"}, methods_json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
2010-08-29 10:10:31 -04:00
|
|
|
|
2017-02-08 11:20:38 -05:00
|
|
|
def test_uses_serializable_hash_with_frozen_hash
|
|
|
|
def @contact.serializable_hash(options = nil)
|
|
|
|
super({ only: %w(name) }.freeze)
|
|
|
|
end
|
|
|
|
|
|
|
|
json = @contact.to_json
|
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_no_match %r{awesome}, json
|
|
|
|
assert_no_match %r{age}, json
|
|
|
|
end
|
|
|
|
|
2012-06-21 23:25:23 -04:00
|
|
|
def test_uses_serializable_hash_with_only_option
|
2016-10-28 23:05:58 -04:00
|
|
|
def @contact.serializable_hash(options = nil)
|
2012-06-21 23:25:23 -04:00
|
|
|
super(only: %w(name))
|
|
|
|
end
|
|
|
|
|
|
|
|
json = @contact.to_json
|
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_no_match %r{awesome}, json
|
|
|
|
assert_no_match %r{age}, json
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_uses_serializable_hash_with_except_option
|
2016-10-28 23:05:58 -04:00
|
|
|
def @contact.serializable_hash(options = nil)
|
2012-06-21 23:25:23 -04:00
|
|
|
super(except: %w(age))
|
|
|
|
end
|
|
|
|
|
|
|
|
json = @contact.to_json
|
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_match %r{"awesome":true}, json
|
|
|
|
assert_no_match %r{age}, json
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_does_not_include_inheritance_column_from_sti
|
|
|
|
@contact = ContactSti.new(@contact.attributes)
|
2016-08-06 12:26:20 -04:00
|
|
|
assert_equal "ContactSti", @contact.type
|
2012-06-21 23:25:23 -04:00
|
|
|
|
|
|
|
json = @contact.to_json
|
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_no_match %r{type}, json
|
|
|
|
assert_no_match %r{ContactSti}, json
|
|
|
|
end
|
|
|
|
|
Fix serializable_hash with xml generation and default :except option
When generating xml with a custom implementation of serializable_hash,
if using the :except option, it was being overriden by the default AR
implementation that attempts to ignore the inheritance column from STI
automatically. So, if you have an implementation like this:
def serializable_hash(options={})
super({ except: %w(some_attr) }.merge!(options))
end
The :except option was correctly being used for :json generation, but
not for :xml, because the options hash already contained the :except
key with the inheritance column, thus overriding the customization.
This commit fixes this problem by removing the :except logic from the
xml serializer, that happened before calling serializable_hash. Since
serializable_hash also does the same check for inheritance column, this
logic was duplicated in both places, thus it's safe to remove it from
xml serializer (see ActiveRecord::Serialization#serializable_hash).
This is an attempt to solve issue #2498, that claims for a
"Single transformation API for both xml and json representations".
2012-06-21 23:27:00 -04:00
|
|
|
def test_serializable_hash_with_default_except_option_and_excluding_inheritance_column_from_sti
|
|
|
|
@contact = ContactSti.new(@contact.attributes)
|
2016-08-06 12:26:20 -04:00
|
|
|
assert_equal "ContactSti", @contact.type
|
Fix serializable_hash with xml generation and default :except option
When generating xml with a custom implementation of serializable_hash,
if using the :except option, it was being overriden by the default AR
implementation that attempts to ignore the inheritance column from STI
automatically. So, if you have an implementation like this:
def serializable_hash(options={})
super({ except: %w(some_attr) }.merge!(options))
end
The :except option was correctly being used for :json generation, but
not for :xml, because the options hash already contained the :except
key with the inheritance column, thus overriding the customization.
This commit fixes this problem by removing the :except logic from the
xml serializer, that happened before calling serializable_hash. Since
serializable_hash also does the same check for inheritance column, this
logic was duplicated in both places, thus it's safe to remove it from
xml serializer (see ActiveRecord::Serialization#serializable_hash).
This is an attempt to solve issue #2498, that claims for a
"Single transformation API for both xml and json representations".
2012-06-21 23:27:00 -04:00
|
|
|
|
2016-10-28 23:05:58 -04:00
|
|
|
def @contact.serializable_hash(options = {})
|
Fix serializable_hash with xml generation and default :except option
When generating xml with a custom implementation of serializable_hash,
if using the :except option, it was being overriden by the default AR
implementation that attempts to ignore the inheritance column from STI
automatically. So, if you have an implementation like this:
def serializable_hash(options={})
super({ except: %w(some_attr) }.merge!(options))
end
The :except option was correctly being used for :json generation, but
not for :xml, because the options hash already contained the :except
key with the inheritance column, thus overriding the customization.
This commit fixes this problem by removing the :except logic from the
xml serializer, that happened before calling serializable_hash. Since
serializable_hash also does the same check for inheritance column, this
logic was duplicated in both places, thus it's safe to remove it from
xml serializer (see ActiveRecord::Serialization#serializable_hash).
This is an attempt to solve issue #2498, that claims for a
"Single transformation API for both xml and json representations".
2012-06-21 23:27:00 -04:00
|
|
|
super({ except: %w(age) }.merge!(options))
|
|
|
|
end
|
|
|
|
|
|
|
|
json = @contact.to_json
|
|
|
|
assert_match %r{"name":"Konata Izumi"}, json
|
|
|
|
assert_no_match %r{age}, json
|
|
|
|
assert_no_match %r{type}, json
|
|
|
|
assert_no_match %r{ContactSti}, json
|
|
|
|
end
|
|
|
|
|
2010-08-29 10:10:31 -04:00
|
|
|
def test_serializable_hash_should_not_modify_options_in_argument
|
2016-06-28 21:32:49 -04:00
|
|
|
options = { only: :name }.freeze
|
|
|
|
assert_nothing_raised { @contact.serializable_hash(options) }
|
2010-08-29 10:10:31 -04:00
|
|
|
end
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
2008-01-21 12:20:51 -05:00
|
|
|
class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase
|
2017-04-27 02:44:25 -04:00
|
|
|
fixtures :authors, :author_addresses, :posts, :comments, :tags, :taggings
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2013-03-04 15:12:18 -05:00
|
|
|
include JsonSerializationHelpers
|
|
|
|
|
2007-09-28 17:11:14 -04:00
|
|
|
def setup
|
|
|
|
@david = authors(:david)
|
2007-10-03 23:28:42 -04:00
|
|
|
@mary = authors(:mary)
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_includes_uses_association_name
|
2016-08-06 13:37:57 -04:00
|
|
|
json = @david.to_json(include: :posts)
|
2007-10-03 23:28:42 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"posts":\[}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"id":1}, json
|
|
|
|
assert_match %r{"name":"David"}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"author_id":1}, json
|
|
|
|
assert_match %r{"title":"Welcome to the weblog"}, json
|
|
|
|
assert_match %r{"body":"Such a lovely day"}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"title":"So I was thinking"}, json
|
|
|
|
assert_match %r{"body":"Like I hopefully always am"}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_includes_uses_association_name_and_applies_attribute_filters
|
2016-08-06 13:37:57 -04:00
|
|
|
json = @david.to_json(include: { posts: { only: :title } })
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"name":"David"}, json
|
|
|
|
assert_match %r{"posts":\[}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"title":"Welcome to the weblog"}, json
|
|
|
|
assert_no_match %r{"body":"Such a lovely day"}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"title":"So I was thinking"}, json
|
|
|
|
assert_no_match %r{"body":"Like I hopefully always am"}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_includes_fetches_second_level_associations
|
2016-08-06 13:37:57 -04:00
|
|
|
json = @david.to_json(include: { posts: { include: { comments: { only: :body } } } })
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"name":"David"}, json
|
|
|
|
assert_match %r{"posts":\[}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"comments":\[}, json
|
|
|
|
assert_match %r{\{"body":"Thank you again for the welcome"\}}, json
|
|
|
|
assert_match %r{\{"body":"Don't think too hard"\}}, json
|
|
|
|
assert_no_match %r{"post_id":}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_includes_fetches_nth_level_associations
|
|
|
|
json = @david.to_json(
|
2016-08-06 13:37:57 -04:00
|
|
|
include: {
|
|
|
|
posts: {
|
|
|
|
include: {
|
|
|
|
taggings: {
|
|
|
|
include: {
|
|
|
|
tag: { only: :name }
|
2007-09-28 17:11:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"name":"David"}, json
|
|
|
|
assert_match %r{"posts":\[}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"taggings":\[}, json
|
|
|
|
assert_match %r{"tag":\{"name":"General"\}}, json
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
|
|
|
|
2011-05-26 10:44:49 -04:00
|
|
|
def test_includes_doesnt_merge_opts_from_base
|
|
|
|
json = @david.to_json(
|
2016-08-06 13:37:57 -04:00
|
|
|
only: :id,
|
|
|
|
include: :posts
|
2011-05-26 10:44:49 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
assert_match %{"title":"Welcome to the weblog"}, json
|
|
|
|
end
|
|
|
|
|
2007-09-28 17:11:14 -04:00
|
|
|
def test_should_not_call_methods_on_associations_that_dont_respond
|
|
|
|
def @david.favorite_quote; "Constraints are liberating"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
json = @david.to_json(include: :posts, methods: :favorite_quote)
|
2007-09-28 17:11:14 -04:00
|
|
|
|
2018-01-24 21:14:10 -05:00
|
|
|
assert_not_respond_to @david.posts.first, :favorite_quote
|
2009-04-23 03:08:40 -04:00
|
|
|
assert_match %r{"favorite_quote":"Constraints are liberating"}, json
|
2016-12-25 21:04:41 -05:00
|
|
|
assert_equal 1, %r{"favorite_quote":}.match(json).size
|
2007-09-28 17:11:14 -04:00
|
|
|
end
|
2007-10-03 23:28:42 -04:00
|
|
|
|
|
|
|
def test_should_allow_only_option_for_list_of_authors
|
2013-03-04 15:12:18 -05:00
|
|
|
set_include_root_in_json(false) do
|
|
|
|
authors = [@david, @mary]
|
|
|
|
assert_equal %([{"name":"David"},{"name":"Mary"}]), ActiveSupport::JSON.encode(authors, only: :name)
|
|
|
|
end
|
2007-10-03 23:28:42 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_should_allow_except_option_for_list_of_authors
|
2013-03-04 15:12:18 -05:00
|
|
|
set_include_root_in_json(false) do
|
|
|
|
authors = [@david, @mary]
|
|
|
|
encoded = ActiveSupport::JSON.encode(authors, except: [
|
|
|
|
:name, :author_address_id, :author_address_extra_id,
|
|
|
|
:organization_id, :owned_essay_id
|
|
|
|
])
|
|
|
|
assert_equal %([{"id":1},{"id":2}]), encoded
|
|
|
|
end
|
2007-10-03 23:28:42 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_should_allow_includes_for_list_of_authors
|
|
|
|
authors = [@david, @mary]
|
2009-06-08 22:25:56 -04:00
|
|
|
json = ActiveSupport::JSON.encode(authors,
|
2016-08-06 13:37:57 -04:00
|
|
|
only: :name,
|
|
|
|
include: {
|
|
|
|
posts: { only: :id }
|
2007-10-03 23:28:42 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2009-04-23 03:08:40 -04:00
|
|
|
['"name":"David"', '"posts":[', '{"id":1}', '{"id":2}', '{"id":4}',
|
2010-10-03 06:56:32 -04:00
|
|
|
'{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[', '{"id":7}', '{"id":9}'].each do |fragment|
|
2016-09-16 12:44:05 -04:00
|
|
|
assert_includes json, fragment, json
|
2007-10-05 20:40:28 -04:00
|
|
|
end
|
2007-10-03 23:28:42 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_should_allow_options_for_hash_of_authors
|
2013-03-04 15:12:18 -05:00
|
|
|
set_include_root_in_json(true) do
|
|
|
|
authors_hash = {
|
|
|
|
1 => @david,
|
|
|
|
2 => @mary
|
|
|
|
}
|
|
|
|
assert_equal %({"1":{"author":{"name":"David"}}}), ActiveSupport::JSON.encode(authors_hash, only: [1, :name])
|
|
|
|
end
|
2007-10-03 23:28:42 -04:00
|
|
|
end
|
2010-07-08 16:17:21 -04:00
|
|
|
|
|
|
|
def test_should_be_able_to_encode_relation
|
2013-03-04 15:12:18 -05:00
|
|
|
set_include_root_in_json(true) do
|
2021-03-29 13:18:53 -04:00
|
|
|
authors_relation = Author.where(id: [@david.id, @mary.id]).order(:id)
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2013-03-04 15:12:18 -05:00
|
|
|
json = ActiveSupport::JSON.encode authors_relation, only: :name
|
|
|
|
assert_equal '[{"author":{"name":"David"}},{"author":{"name":"Mary"}}]', json
|
|
|
|
end
|
2010-07-08 16:17:21 -04:00
|
|
|
end
|
2007-10-05 20:33:51 -04:00
|
|
|
end
|