From e47231cdc8ab904614e192ec67031df42afa6c71 Mon Sep 17 00:00:00 2001 From: Alexandre de Oliveira Date: Thu, 29 Jan 2015 16:48:41 -0200 Subject: [PATCH 1/2] Support overriding association methods You can override associations to define custom scope on them. --- README.md | 16 ++++++++++ lib/active_model/serializer.rb | 4 ++- .../action_controller/json_api_linked_test.rb | 3 ++ test/adapter/json/belongs_to_test.rb | 5 ++- test/adapter/json/collection_test.rb | 32 ++++++++++++++++--- test/adapter/json/has_many_test.rb | 2 ++ test/adapter/json_api/belongs_to_test.rb | 9 +++++- test/adapter/json_api/collection_test.rb | 11 ++++--- .../json_api/has_many_embed_ids_test.rb | 3 ++ .../has_many_explicit_serializer_test.rb | 2 ++ test/adapter/json_api/has_many_test.rb | 4 ++- test/adapter/json_api/linked_test.rb | 6 ++++ test/adapter/json_test.rb | 2 ++ test/fixtures/poro.rb | 5 +++ test/serializers/associations_test.rb | 15 ++++++++- 15 files changed, 106 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 714b37669..c5fee72c1 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,22 @@ call: render json: @post, root: "articles" ``` +### Overriding association methods + +If you want to override any association, you can use: + +```ruby +class PostSerializer < ActiveModel::Serializer + attributes :id, :body + + has_many :comments + + def comments + object.comments.active + end +end +``` + ### Built in Adapters #### JSONAPI diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index d4087fe6b..e5d361a78 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -149,10 +149,12 @@ def attributes(options = {}) def each_association(&block) self.class._associations.dup.each do |name, options| next unless object + association = object.send(name) + association_value = send(name) serializer_class = ActiveModel::Serializer.serializer_for(association, options) serializer = serializer_class.new( - association, + association_value, serializer_from_options(options) ) if serializer_class diff --git a/test/action_controller/json_api_linked_test.rb b/test/action_controller/json_api_linked_test.rb index 71b69b0ec..80f50ca5a 100644 --- a/test/action_controller/json_api_linked_test.rb +++ b/test/action_controller/json_api_linked_test.rb @@ -29,6 +29,9 @@ def setup_post @post2 = Post.new(id: 2, title: "Another Post", body: "Body") @post2.author = @author @post2.comments = [] + @blog = Blog.new(id: 1, name: "My Blog!!") + @post.blog = @blog + @post2.blog = @blog end def render_resource_without_include diff --git a/test/adapter/json/belongs_to_test.rb b/test/adapter/json/belongs_to_test.rb index ea1186475..bb983f728 100644 --- a/test/adapter/json/belongs_to_test.rb +++ b/test/adapter/json/belongs_to_test.rb @@ -15,6 +15,9 @@ def setup @comment.post = @post @comment.author = nil @anonymous_post.author = nil + @blog = Blog.new(id: 1, name: "My Blog!!") + @post.blog = @blog + @anonymous_post.blog = nil @serializer = CommentSerializer.new(@comment) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) @@ -28,7 +31,7 @@ def test_include_nil_author serializer = PostSerializer.new(@anonymous_post) adapter = ActiveModel::Serializer::Adapter::Json.new(serializer) - assert_equal({title: "Hello!!", body: "Hello, world!!", id: 43, comments: [], author: nil}, adapter.serializable_hash) + assert_equal({title: "Hello!!", body: "Hello, world!!", id: 43, comments: [], blog: nil, author: nil}, adapter.serializable_hash) end end end diff --git a/test/adapter/json/collection_test.rb b/test/adapter/json/collection_test.rb index 51af54489..0742333ad 100644 --- a/test/adapter/json/collection_test.rb +++ b/test/adapter/json/collection_test.rb @@ -13,16 +13,40 @@ def setup @second_post.comments = [] @first_post.author = @author @second_post.author = @author + @blog = Blog.new(id: 1, name: "My Blog!!") + @first_post.blog = @blog + @second_post.blog = nil @serializer = ArraySerializer.new([@first_post, @second_post]) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) end def test_include_multiple_posts - assert_equal([ - {title: "Hello!!", body: "Hello, world!!", id: 1, comments: [], author: {id: 1, name: "Steve K."}}, - {title: "New Post", body: "Body", id: 2, comments: [], author: {id: 1, name: "Steve K."}} - ], @adapter.serializable_hash) + expected = [{ + title: "Hello!!", + body: "Hello, world!!", + id: 1, + comments: [], + author: { + id: 1, + name: "Steve K." + }, + blog: { + id: 999, + name: "Custom blog" + } + }, { + title: "New Post", + body: "Body", + id: 2, + comments: [], + author: { + id: 1, + name: "Steve K." + }, + blog: nil + }] + assert_equal expected, @adapter.serializable_hash end end end diff --git a/test/adapter/json/has_many_test.rb b/test/adapter/json/has_many_test.rb index 77f672c70..c5679e681 100644 --- a/test/adapter/json/has_many_test.rb +++ b/test/adapter/json/has_many_test.rb @@ -14,6 +14,8 @@ def setup @post.author = @author @first_comment.post = @post @second_comment.post = @post + @blog = Blog.new(id: 1, name: "My Blog!!") + @post.blog = @blog @serializer = PostSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) diff --git a/test/adapter/json_api/belongs_to_test.rb b/test/adapter/json_api/belongs_to_test.rb index 30397a30c..678e6a245 100644 --- a/test/adapter/json_api/belongs_to_test.rb +++ b/test/adapter/json_api/belongs_to_test.rb @@ -9,11 +9,14 @@ def setup @author = Author.new(id: 1, name: 'Steve K.') @author.bio = nil @author.roles = [] + @blog = Blog.new(id: 23, name: 'AMS Blog') @post = Post.new(id: 42, title: 'New Post', body: 'Body') @anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!') @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') @post.comments = [@comment] + @post.blog = @blog @anonymous_post.comments = [] + @anonymous_post.blog = nil @comment.post = @post @comment.author = nil @post.author = @author @@ -39,6 +42,7 @@ def test_includes_linked_post body: 'Body', links: { comments: ["1"], + blog: "999", author: "1" } }] @@ -51,6 +55,7 @@ def test_limiting_linked_post_fields title: 'New Post', links: { comments: ["1"], + blog: "999", author: "1" } }] @@ -61,7 +66,7 @@ def test_include_nil_author serializer = PostSerializer.new(@anonymous_post) adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer) - assert_equal({comments: [], author: nil}, adapter.serializable_hash[:posts][:links]) + assert_equal({comments: [], blog: nil, author: nil}, adapter.serializable_hash[:posts][:links]) end def test_include_type_for_association_when_different_than_name @@ -101,6 +106,7 @@ def test_include_linked_resources_with_type_name id: "42", links: { comments: ["1"], + blog: "999", author: "1" } }, { @@ -109,6 +115,7 @@ def test_include_linked_resources_with_type_name id: "43", links: { comments: [], + blog: nil, author: nil } }] diff --git a/test/adapter/json_api/collection_test.rb b/test/adapter/json_api/collection_test.rb index 205eaf211..5ab06cfe4 100644 --- a/test/adapter/json_api/collection_test.rb +++ b/test/adapter/json_api/collection_test.rb @@ -8,10 +8,13 @@ class CollectionTest < Minitest::Test def setup @author = Author.new(id: 1, name: 'Steve K.') @author.bio = nil + @blog = Blog.new(id: 23, name: 'AMS Blog') @first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!') @second_post = Post.new(id: 2, title: 'New Post', body: 'Body') @first_post.comments = [] @second_post.comments = [] + @first_post.blog = @blog + @second_post.blog = nil @first_post.author = @author @second_post.author = @author @author.posts = [@first_post, @second_post] @@ -22,16 +25,16 @@ def setup def test_include_multiple_posts assert_equal([ - { title: "Hello!!", body: "Hello, world!!", id: "1", links: { comments: [], author: "1" } }, - { title: "New Post", body: "Body", id: "2", links: { comments: [], author: "1" } } + { title: "Hello!!", body: "Hello, world!!", id: "1", links: { comments: [], blog: "999", author: "1" } }, + { title: "New Post", body: "Body", id: "2", links: { comments: [], blog: nil, author: "1" } } ], @adapter.serializable_hash[:posts]) end def test_limiting_fields @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, fields: ['title']) assert_equal([ - { title: "Hello!!", links: { comments: [], author: "1" } }, - { title: "New Post", links: { comments: [], author: "1" } } + { title: "Hello!!", links: { comments: [], blog: "999", author: "1" } }, + { title: "New Post", links: { comments: [], blog: nil, author: "1" } } ], @adapter.serializable_hash[:posts]) end diff --git a/test/adapter/json_api/has_many_embed_ids_test.rb b/test/adapter/json_api/has_many_embed_ids_test.rb index a6072aa4f..0082e5858 100644 --- a/test/adapter/json_api/has_many_embed_ids_test.rb +++ b/test/adapter/json_api/has_many_embed_ids_test.rb @@ -16,6 +16,9 @@ def setup @second_post.author = @author @first_post.comments = [] @second_post.comments = [] + @blog = Blog.new(id: 23, name: 'AMS Blog') + @first_post.blog = @blog + @second_post.blog = nil @serializer = AuthorSerializer.new(@author) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer) diff --git a/test/adapter/json_api/has_many_explicit_serializer_test.rb b/test/adapter/json_api/has_many_explicit_serializer_test.rb index 72b92494b..29e73c4a7 100644 --- a/test/adapter/json_api/has_many_explicit_serializer_test.rb +++ b/test/adapter/json_api/has_many_explicit_serializer_test.rb @@ -18,6 +18,8 @@ def setup @first_comment.author = nil @second_comment.post = @post @second_comment.author = nil + @blog = Blog.new(id: 23, name: 'AMS Blog') + @post.blog = @blog @serializer = PostPreviewSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new( diff --git a/test/adapter/json_api/has_many_test.rb b/test/adapter/json_api/has_many_test.rb index 0d334cac2..b49288828 100644 --- a/test/adapter/json_api/has_many_test.rb +++ b/test/adapter/json_api/has_many_test.rb @@ -24,6 +24,8 @@ def setup @blog = Blog.new(id: 1, name: "My Blog!!") @blog.writer = @author @blog.articles = [@post] + @post.blog = @blog + @post_without_comments.blog = nil @serializer = PostSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer) @@ -32,7 +34,7 @@ def setup def test_includes_comment_ids assert_equal(["1", "2"], @adapter.serializable_hash[:posts][:links][:comments]) end - + def test_includes_linked_comments @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'comments') expected = [{ diff --git a/test/adapter/json_api/linked_test.rb b/test/adapter/json_api/linked_test.rb index efdcbd497..50425325e 100644 --- a/test/adapter/json_api/linked_test.rb +++ b/test/adapter/json_api/linked_test.rb @@ -13,6 +13,10 @@ def setup @first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!') @second_post = Post.new(id: 2, title: 'New Post', body: 'Body') @third_post = Post.new(id: 3, title: 'Yet Another Post', body: 'Body') + @blog = Blog.new({ name: 'AMS Blog' }) + @first_post.blog = @blog + @second_post.blog = @blog + @third_post.blog = nil @first_post.comments = [] @second_post.comments = [] @first_post.author = @author1 @@ -124,6 +128,7 @@ def test_include_multiple_posts_and_linked id: "1", links: { comments: ["1", "2"], + blog: "999", author: "1" } }, { @@ -132,6 +137,7 @@ def test_include_multiple_posts_and_linked id: "3", links: { comments: [], + blog: nil, author: "1" } }] diff --git a/test/adapter/json_test.rb b/test/adapter/json_test.rb index fe573f7b4..5795174eb 100644 --- a/test/adapter/json_test.rb +++ b/test/adapter/json_test.rb @@ -13,6 +13,8 @@ def setup @first_comment.post = @post @second_comment.post = @post @post.author = @author + @blog = Blog.new(id: 1, name: "My Blog!!") + @post.blog = @blog @serializer = PostSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index 3c3068417..9cd982949 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -54,8 +54,13 @@ module Spam; end attributes :title, :body, :id has_many :comments + belongs_to :blog belongs_to :author url :comments + + def blog + Blog.new(id: 999, name: "Custom blog") + end end SpammyPostSerializer = Class.new(ActiveModel::Serializer) do diff --git a/test/serializers/associations_test.rb b/test/serializers/associations_test.rb index 62a152733..3a54bd5c6 100644 --- a/test/serializers/associations_test.rb +++ b/test/serializers/associations_test.rb @@ -28,14 +28,17 @@ def setup @author = Author.new(name: 'Steve K.') @author.bio = nil @author.roles = [] + @blog = Blog.new({ name: 'AMS Blog' }) @post = Post.new({ title: 'New Post', body: 'Body' }) @comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' }) @post.comments = [@comment] + @post.blog = @blog @comment.post = @post @comment.author = nil @post.author = @author @author.posts = [@post] + @post_serializer = PostSerializer.new(@post) @author_serializer = AuthorSerializer.new(@author) @comment_serializer = CommentSerializer.new(@comment) end @@ -63,7 +66,7 @@ def test_has_many end end - def test_has_one + def test_belongs_to assert_equal({post: {type: :belongs_to, association_options: {}}, :author=>{:type=>:belongs_to, :association_options=>{}}}, @comment_serializer.class._associations) @comment_serializer.each_association do |name, serializer, options| if name == :post @@ -77,6 +80,16 @@ def test_has_one end end end + + def test_belongs_to_with_custom_method + blog_is_present = false + + @post_serializer.each_association do |name, serializer, options| + blog_is_present = true if name == :blog + end + + assert blog_is_present + end end end end From e771e637bfc7de845957040cab63267a3b35ae0f Mon Sep 17 00:00:00 2001 From: Alexandre de Oliveira Date: Thu, 29 Jan 2015 16:50:11 -0200 Subject: [PATCH 2/2] Updates CHANGELOG to include association overriding --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d845803dd..8fcaae863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ ### 0.10.0 * adds support for `meta` and `meta_key` [@kurko] + * adds method to override association [adcb99e, @kurko]