diff --git a/lib/toy.rb b/lib/toy.rb
index f7bb5cc..ea33d07 100644
--- a/lib/toy.rb
+++ b/lib/toy.rb
@@ -79,6 +79,7 @@ module Middleware
autoload 'Querying', 'toy/querying'
autoload 'Reloadable', 'toy/reloadable'
autoload 'Serialization', 'toy/serialization'
+ autoload 'AssociationSerialization','toy/association_serialization'
autoload 'Timestamps', 'toy/timestamps'
autoload 'Validations', 'toy/validations'
@@ -101,4 +102,4 @@ module Identity
require 'toy/object'
require 'toy/store'
-Toy::IdentityMap.enabled = false
\ No newline at end of file
+Toy::IdentityMap.enabled = false
diff --git a/lib/toy/association_serialization.rb b/lib/toy/association_serialization.rb
new file mode 100644
index 0000000..64e9337
--- /dev/null
+++ b/lib/toy/association_serialization.rb
@@ -0,0 +1,50 @@
+module Toy
+ module AssociationSerialization
+ extend ActiveSupport::Concern
+ include Serialization
+
+ def serializable_hash(options = nil)
+ options ||= {}
+ super.tap { |hash|
+ serializable_add_includes(options) do |association, records, opts|
+ hash[association] = records.is_a?(Enumerable) ?
+ records.map { |r| r.serializable_hash(opts) } :
+ records.serializable_hash(opts)
+ end
+ }
+ end
+
+ private
+
+ # Add associations specified via the :includes option.
+ # Expects a block that takes as arguments:
+ # +association+ - name of the association
+ # +records+ - the association record(s) to be serialized
+ # +opts+ - options for the association records
+ def serializable_add_includes(options = {})
+ return unless include_associations = options.delete(:include)
+
+ base_only_or_except = { :except => options[:except],
+ :only => options[:only] }
+
+ include_has_options = include_associations.is_a?(Hash)
+ associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
+
+ for association in associations
+ records = if self.class.list?(association)
+ send(association).to_a
+ elsif self.class.reference?(association) || self.class.parent_reference?(association)
+ send(association)
+ end
+
+ unless records.nil?
+ association_options = include_has_options ? include_associations[association] : base_only_or_except
+ opts = options.merge(association_options)
+ yield(association, records, opts)
+ end
+ end
+
+ options[:include] = include_associations
+ end
+ end
+end
diff --git a/lib/toy/object.rb b/lib/toy/object.rb
index 192bd52..7cbe123 100644
--- a/lib/toy/object.rb
+++ b/lib/toy/object.rb
@@ -12,6 +12,7 @@ module Object
include Inspect
include Logger
include Inheritance
+ include Serialization
end
def persisted?
diff --git a/lib/toy/serialization.rb b/lib/toy/serialization.rb
index d1be65d..9f98789 100644
--- a/lib/toy/serialization.rb
+++ b/lib/toy/serialization.rb
@@ -37,46 +37,7 @@ def serializable_hash(options = nil)
end
end
- serializable_add_includes(options) do |association, records, opts|
- hash[association] = records.is_a?(Enumerable) ?
- records.map { |r| r.serializable_hash(opts) } :
- records.serializable_hash(opts)
- end
-
hash
end
-
- private
-
- # Add associations specified via the :includes option.
- # Expects a block that takes as arguments:
- # +association+ - name of the association
- # +records+ - the association record(s) to be serialized
- # +opts+ - options for the association records
- def serializable_add_includes(options = {})
- return unless include_associations = options.delete(:include)
-
- base_only_or_except = { :except => options[:except],
- :only => options[:only] }
-
- include_has_options = include_associations.is_a?(Hash)
- associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
-
- for association in associations
- records = if self.class.list?(association)
- send(association).to_a
- elsif self.class.reference?(association) || self.class.parent_reference?(association)
- send(association)
- end
-
- unless records.nil?
- association_options = include_has_options ? include_associations[association] : base_only_or_except
- opts = options.merge(association_options)
- yield(association, records, opts)
- end
- end
-
- options[:include] = include_associations
- end
end
-end
\ No newline at end of file
+end
diff --git a/lib/toy/store.rb b/lib/toy/store.rb
index 12478b5..c7f8a1f 100644
--- a/lib/toy/store.rb
+++ b/lib/toy/store.rb
@@ -13,14 +13,14 @@ module Store
include Callbacks
include Validations
- include Serialization
include Timestamps
include Lists
include References
+ include AssociationSerialization
include IdentityMap
include Caching
end
end
-end
\ No newline at end of file
+end
diff --git a/spec/toy/association_serialization_spec.rb b/spec/toy/association_serialization_spec.rb
new file mode 100644
index 0000000..788b871
--- /dev/null
+++ b/spec/toy/association_serialization_spec.rb
@@ -0,0 +1,103 @@
+require 'helper'
+
+describe Toy::AssociationSerialization do
+ uses_constants('User', 'Game', 'Move')
+
+ before do
+ User.attribute :name, String
+ User.attribute :age, Integer
+ end
+
+ describe "serializing relationships" do
+ before do
+ User.list :games, :inverse_of => :user
+ Game.reference :user
+ end
+
+ it "should include references" do
+ user = User.create(:name => 'John', :age => 28)
+ game = user.games.create
+
+ MultiJson.load(game.to_json(:include => [:user])).should == {
+ 'game' => {
+ 'id' => game.id,
+ 'user_id' => user.id,
+ 'user' => {
+ 'name' => 'John',
+ 'game_ids' => [game.id],
+ 'id' => user.id,
+ 'age' => 28,
+ }
+ }
+ }
+ end
+
+ it "should include lists" do
+ user = User.create(:name => 'John', :age => 28)
+ game = user.games.create
+ MultiJson.load(user.to_json(:include => [:games])).should == {
+ 'user' => {
+ 'name' => 'John',
+ 'game_ids' => [game.id],
+ 'id' => user.id,
+ 'age' => 28,
+ 'games' => [{'id' => game.id, 'user_id' => user.id}],
+ }
+ }
+ end
+
+ it "should not cause circular reference JSON errors for references" do
+ user = User.create(:name => 'John', :age => 28)
+ game = user.games.create
+
+ MultiJson.load(ActiveSupport::JSON.encode(game.user)).should == {
+ 'user' => {
+ 'name' => 'John',
+ 'game_ids' => [game.id],
+ 'id' => user.id,
+ 'age' => 28
+ }
+ }
+ end
+
+ it "should not cause circular reference JSON errors for references when called indirectly" do
+ user = User.create(:name => 'John', :age => 28)
+ game = user.games.create
+
+ MultiJson.load(ActiveSupport::JSON.encode([game.user])).should == [
+ 'user' => {
+ 'name' => 'John',
+ 'game_ids' => [game.id],
+ 'id' => user.id,
+ 'age' => 28
+ }
+ ]
+ end
+
+ it "should not cause circular reference JSON errors for lists" do
+ user = User.create(:name => 'John', :age => 28)
+ game = user.games.create
+
+ MultiJson.load(ActiveSupport::JSON.encode(user.games)).should == [{
+ 'game' => {
+ 'id' => game.id,
+ 'user_id' => user.id
+ }
+ }]
+ end
+
+ it "should not cause circular reference JSON errors for lists when called indirectly" do
+ user = User.create(:name => 'John', :age => 28)
+ game = user.games.create
+
+ MultiJson.load(ActiveSupport::JSON.encode({:games => user.games})).should == {
+ 'games' => [{
+ 'game' => {
+ 'id' => game.id,
+ 'user_id' => user.id
+ }
+ }]
+ }
+ end
+ end
+end
diff --git a/spec/toy/serialization_spec.rb b/spec/toy/serialization_spec.rb
index b1948ae..c7d4c60 100644
--- a/spec/toy/serialization_spec.rb
+++ b/spec/toy/serialization_spec.rb
@@ -1,7 +1,7 @@
require 'helper'
describe Toy::Serialization do
- uses_constants('User', 'Game', 'Move')
+ uses_objects('User', 'Move')
before do
User.attribute :name, String
@@ -28,7 +28,6 @@
'age' => 28
}
}
-
end
it "correctly serializes methods" do
@@ -65,99 +64,6 @@ def foo
MultiJson.load(json)['user'].should_not have_key('id')
end
- describe "serializing relationships" do
- before do
- User.list :games, :inverse_of => :user
- Game.reference :user
- end
-
- it "should include references" do
- user = User.create(:name => 'John', :age => 28)
- game = user.games.create
-
- MultiJson.load(game.to_json(:include => [:user])).should == {
- 'game' => {
- 'id' => game.id,
- 'user_id' => user.id,
- 'user' => {
- 'name' => 'John',
- 'game_ids' => [game.id],
- 'id' => user.id,
- 'age' => 28,
- }
- }
- }
- end
-
- it "should include lists" do
- user = User.create(:name => 'John', :age => 28)
- game = user.games.create
- MultiJson.load(user.to_json(:include => [:games])).should == {
- 'user' => {
- 'name' => 'John',
- 'game_ids' => [game.id],
- 'id' => user.id,
- 'age' => 28,
- 'games' => [{'id' => game.id, 'user_id' => user.id}],
- }
- }
- end
-
- it "should not cause circular reference JSON errors for references" do
- user = User.create(:name => 'John', :age => 28)
- game = user.games.create
-
- MultiJson.load(ActiveSupport::JSON.encode(game.user)).should == {
- 'user' => {
- 'name' => 'John',
- 'game_ids' => [game.id],
- 'id' => user.id,
- 'age' => 28
- }
- }
- end
-
- it "should not cause circular reference JSON errors for references when called indirectly" do
- user = User.create(:name => 'John', :age => 28)
- game = user.games.create
-
- MultiJson.load(ActiveSupport::JSON.encode([game.user])).should == [
- 'user' => {
- 'name' => 'John',
- 'game_ids' => [game.id],
- 'id' => user.id,
- 'age' => 28
- }
- ]
- end
-
- it "should not cause circular reference JSON errors for lists" do
- user = User.create(:name => 'John', :age => 28)
- game = user.games.create
-
- MultiJson.load(ActiveSupport::JSON.encode(user.games)).should == [{
- 'game' => {
- 'id' => game.id,
- 'user_id' => user.id
- }
- }]
- end
-
- it "should not cause circular reference JSON errors for lists when called indirectly" do
- user = User.create(:name => 'John', :age => 28)
- game = user.games.create
-
- MultiJson.load(ActiveSupport::JSON.encode({:games => user.games})).should == {
- 'games' => [{
- 'game' => {
- 'id' => game.id,
- 'user_id' => user.id
- }
- }]
- }
- end
- end
-
describe "serializing specific attributes" do
before do
Move.attribute(:index, Integer)
@@ -228,16 +134,15 @@ def calculated_attribute
describe "#serializable_hash" do
context "with method that is another toystore object" do
before do
- Game.reference(:creator, User)
- @game = Game.create(:creator => User.create)
+ Move.class_eval { attr_accessor :creator }
end
- let(:game) { @game }
+
+ let(:move) { Move.new(:creator => User.new) }
it "returns serializable hash of object" do
- game.serializable_hash(:methods => [:creator]).should == {
- 'id' => game.id,
- 'creator_id' => game.creator_id,
- 'creator' => {'id' => game.creator.id}
+ move.serializable_hash(:methods => [:creator]).should == {
+ 'id' => move.id,
+ 'creator' => {'id' => move.creator.id}
}
end
end