From 498c780a8f569a4124b58302b33a33eb7bce5fac Mon Sep 17 00:00:00 2001 From: Adman65 Date: Tue, 6 Dec 2011 15:27:47 +0200 Subject: [PATCH] Closes #4 --- README.textile | 27 ++++++++++++ lib/active_model/serializer.rb | 19 ++++++-- test/serializer_test.rb | 81 +++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/README.textile b/README.textile index 8cd1cd3c..f31a0ddb 100644 --- a/README.textile +++ b/README.textile @@ -351,6 +351,32 @@ for the current user. NOTE: The logic for deciding which comments a user should see still belongs in the model layer. In general, you should encapsulate concerns that require making direct Active Record queries in scopes or public methods on your models. +h4. Modifying Associations + +You can also rename associations if required. Say for example you have an association that +makes sense to be named one thing in your code, but another when data is serialized. +You can use the :as option to specify a different name for an association. +Here is an exmaple: + +
+class UserSerializer < ActiveModel::Serializer
+  has_many :followed_posts, :as => :posts
+  has_one :owne_account, :as => :account
+end
+
+ +Using the :as without a :serializer option will use implicit detection +to determine a serializer. In this example, you'd have to define two classes: PostSerializer +and AccountSerializer. You can also add the :serializer option +to set it explicitly: + +
+class UserSerializer < ActiveModel::Serializer
+  has_many :followed_posts, :as => :posts, :serializer => CustomPostSerializer
+  has_one :owne_account, :as => :account, :serializer => PrivateAccountSerializer
+end
+
+ h3. Customizing Associations Not all front-ends expect embedded documents in the same form. In these cases, you can override the @@ -431,6 +457,7 @@ The +association_ids+ helper will use the overridden version of the association, this case, +association_ids+ will only include the ids of the comments provided by the +comments+ method. + h3. Special Association Serializers So far, associations defined in serializers use either the +as_json+ method on the model diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 0e23df2f..72c9065f 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -68,6 +68,10 @@ module ActiveModel def serializer options[:serializer] end + + def key + options[:as] || name + end end class HasMany < Config #:nodoc: @@ -122,7 +126,14 @@ module ActiveModel class_eval "def #{attr}() object.#{attr} end", __FILE__, __LINE__ end - options[:serializer] ||= const_get("#{attr.to_s.camelize}Serializer") + # if :as is specified without :serializer, then use conventions + # to determine the serializer + if options[:as] && !options[:serializer] + options[:serializer] = const_get("#{options[:as].to_s.camelize.singularize}Serializer") + else + options[:serializer] ||= const_get("#{attr.to_s.camelize}Serializer") + end + klass.new(attr, options) end end @@ -212,7 +223,7 @@ module ActiveModel _associations.each do |association| associated_object = send(association.name) - hash[association.name] = association.serialize(associated_object, scope) + hash[association.key] = association.serialize(associated_object, scope) end hash @@ -225,7 +236,7 @@ module ActiveModel _associations.each do |association| associated_object = send(association.name) - hash[association.name] = association.serialize_ids(associated_object, scope) + hash[association.key] = association.serialize_ids(associated_object, scope) end hash @@ -250,4 +261,4 @@ class Array def active_model_serializer ActiveModel::ArraySerializer end -end \ No newline at end of file +end diff --git a/test/serializer_test.rb b/test/serializer_test.rb index 2c390fe3..b09e0e4c 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -34,6 +34,11 @@ class SerializerTest < ActiveModel::TestCase end class Post < Model + def initialize(attributes) + super(attributes) + self.comments ||= [] + end + attr_accessor :comments def active_model_serializer; PostSerializer; end end @@ -429,4 +434,78 @@ class SerializerTest < ActiveModel::TestCase { :comment => { :title => "Comment1" } } ], serializer.as_json) end -end \ No newline at end of file + + class CustomBlog < Blog + attr_accessor :public_posts, :public_user + end + + class CustomBlogSerializer < ActiveModel::Serializer + has_many :public_posts, :as => :posts, :serializer => PostSerializer + has_one :public_user, :as => :user, :serializer => UserSerializer + end + + def test_associations_with_as + posts = [ + Post.new(:title => 'First Post', :body => 'text'), + Post.new(:title => 'Second Post', :body => 'text') + ] + user = User.new + + custom_blog = CustomBlog.new + custom_blog.public_posts = posts + custom_blog.public_user = user + + serializer = CustomBlogSerializer.new(custom_blog, :scope => true) + + assert_equal({ + :custom_blog => { + :posts => [ + {:title => 'First Post', :body => 'text', :comments => []}, + {:title => 'Second Post', :body => 'text', :comments => []} + ], + :user => { + :first_name => "Jose", + :last_name => "Valim", :ok => true, + :scope => true + } + } + }, serializer.as_json) + end + + def test_implicity_detection_for_association_serializers + implicit_serializer = Class.new(ActiveModel::Serializer) do + root :custom_blog + const_set(:UserSerializer, UserSerializer) + const_set(:PostSerializer, PostSerializer) + + has_many :public_posts, :as => :posts + has_one :public_user, :as => :user + end + + posts = [ + Post.new(:title => 'First Post', :body => 'text', :comments => []), + Post.new(:title => 'Second Post', :body => 'text', :comments => []) + ] + user = User.new + + custom_blog = CustomBlog.new + custom_blog.public_posts = posts + custom_blog.public_user = user + + serializer = implicit_serializer.new(custom_blog, :scope => true) + + assert_equal({ + :custom_blog => { + :posts => [ + {:title => 'First Post', :body => 'text', :comments => []}, + {:title => 'Second Post', :body => 'text', :comments => []} + ], + :user => { + :first_name => "Jose", + :last_name => "Valim", :ok => true, + :scope => true + } + } + }, serializer.as_json) + end +end