From 0d3999c36d4ac7d6fdc17b8482a118d06282a633 Mon Sep 17 00:00:00 2001 From: Konstantin Munteanu Date: Sat, 1 Sep 2018 13:30:51 +0200 Subject: [PATCH 1/3] Support conditions in link statements --- CHANGELOG.md | 1 + docs/general/serializers.md | 9 ++++++++ lib/active_model/serializer.rb | 10 +++++++-- lib/active_model/serializer/link.rb | 21 +++++++++++++++++++ .../adapter/json_api.rb | 4 ++++ test/adapter/json_api/links_test.rb | 17 ++++++++++++++- 6 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 lib/active_model/serializer/link.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 997e08ce..95089a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Breaking changes: Features: +- [#2279](https://github.com/rails-api/active_model_serializers/pull/2279) Support condition options in serializer link statements Fixes: diff --git a/docs/general/serializers.md b/docs/general/serializers.md index 2e8bcd31..b9deb78c 100644 --- a/docs/general/serializers.md +++ b/docs/general/serializers.md @@ -238,6 +238,15 @@ link :other, 'https://example.com/resource' link(:posts) { link_author_posts_url(object) } ``` +Just like attributes, links also support conditions in options +```ruby +link(:secret, if: :internal?) { object.secret_link } + +def internal? + instance_options[:context] == :internal +end +``` + #### #object The object being serialized. diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index f6567a70..b49ba5cf 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -22,6 +22,7 @@ module ActiveModel autoload :Adapter autoload :Null autoload :Attribute + autoload :Link autoload :Association autoload :Reflection autoload :BelongsToReflection @@ -275,9 +276,14 @@ module ActiveModel # link(:self) { "http://example.com/resource/#{object.id}" } # @example # link :resource, "http://example.com/resource" + # @example + # link(:callback, if: :internal?), { "http://example.com/callback" } # - def self.link(name, value = nil, &block) - _links[name] = block || value + def self.link(name, *args, &block) + options = args.extract_options! + # For compatibility with the use cae of passing link directly as string argument + # without block, we are creating a wrapping block + _links[name] = Link.new(name, options, block || ->(_serializer) { args.first }) end # Set the JSON API meta attribute of a serializer. diff --git a/lib/active_model/serializer/link.rb b/lib/active_model/serializer/link.rb new file mode 100644 index 00000000..9bf7f1eb --- /dev/null +++ b/lib/active_model/serializer/link.rb @@ -0,0 +1,21 @@ +require 'active_model/serializer/field' + +module ActiveModel + class Serializer + # Holds all the data about an serializer link + # + # @example + # class PostSerializer < ActiveModel::Serializer + # link :callback, if: :internal? do + # object.callback_link + # end + # + # def internal? + # instance_options[:internal] == true + # end + # end + # + class Link < Field + end + end +end diff --git a/lib/active_model_serializers/adapter/json_api.rb b/lib/active_model_serializers/adapter/json_api.rb index 592a9e9e..1b2b5105 100644 --- a/lib/active_model_serializers/adapter/json_api.rb +++ b/lib/active_model_serializers/adapter/json_api.rb @@ -482,6 +482,10 @@ module ActiveModelSerializers # }.reject! {|_,v| v.nil? } def links_for(serializer) serializer._links.each_with_object({}) do |(name, value), hash| + if value.is_a?(ActiveModel::Serializer::Link) + next if value.excluded?(serializer) + value = value.block + end result = Link.new(serializer, value).as_json hash[name] = result if result end diff --git a/test/adapter/json_api/links_test.rb b/test/adapter/json_api/links_test.rb index ffbfa303..e310b283 100644 --- a/test/adapter/json_api/links_test.rb +++ b/test/adapter/json_api/links_test.rb @@ -17,7 +17,21 @@ module ActiveModelSerializers link :yet_another do "http://example.com/resource/#{object.id}" end + link :conditional1, if: -> { instance_truth } do + "http://example.com/conditional1/#{object.id}" + end + link :conditional2, if: :instance_falsey do + "http://example.com/conditional2/#{object.id}" + end link(:nil) { nil } + + def instance_truth + true + end + + def instance_falsey + false + end end def setup @@ -85,7 +99,8 @@ module ActiveModelSerializers :"link-authors" => 'http://example.com/link_authors', resource: 'http://example.com/resource', posts: 'http://example.com/link_authors/1337/posts', - :"yet-another" => 'http://example.com/resource/1337' + :"yet-another" => 'http://example.com/resource/1337', + conditional1: 'http://example.com/conditional1/1337' } assert_equal(expected, hash[:data][:links]) end From ca6c009273e1cdfca626ee19b99043da0dc51518 Mon Sep 17 00:00:00 2001 From: Konstantin Munteanu Date: Thu, 6 Sep 2018 10:45:31 +0200 Subject: [PATCH 2/3] typos --- lib/active_model/serializer.rb | 2 +- lib/active_model/serializer/link.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index b49ba5cf..dddb465c 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -281,7 +281,7 @@ module ActiveModel # def self.link(name, *args, &block) options = args.extract_options! - # For compatibility with the use cae of passing link directly as string argument + # For compatibility with the use case of passing link directly as string argument # without block, we are creating a wrapping block _links[name] = Link.new(name, options, block || ->(_serializer) { args.first }) end diff --git a/lib/active_model/serializer/link.rb b/lib/active_model/serializer/link.rb index 9bf7f1eb..934624d4 100644 --- a/lib/active_model/serializer/link.rb +++ b/lib/active_model/serializer/link.rb @@ -2,7 +2,7 @@ require 'active_model/serializer/field' module ActiveModel class Serializer - # Holds all the data about an serializer link + # Holds all the data about a serializer link # # @example # class PostSerializer < ActiveModel::Serializer From 572f11b7e0592eb0781006b9c364d8bd13474831 Mon Sep 17 00:00:00 2001 From: Konstantin Munteanu Date: Thu, 25 Oct 2018 09:54:36 +0200 Subject: [PATCH 3/3] value is always a link --- lib/active_model_serializers/adapter/json_api.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/active_model_serializers/adapter/json_api.rb b/lib/active_model_serializers/adapter/json_api.rb index 1b2b5105..c4693854 100644 --- a/lib/active_model_serializers/adapter/json_api.rb +++ b/lib/active_model_serializers/adapter/json_api.rb @@ -482,11 +482,8 @@ module ActiveModelSerializers # }.reject! {|_,v| v.nil? } def links_for(serializer) serializer._links.each_with_object({}) do |(name, value), hash| - if value.is_a?(ActiveModel::Serializer::Link) - next if value.excluded?(serializer) - value = value.block - end - result = Link.new(serializer, value).as_json + next if value.excluded?(serializer) + result = Link.new(serializer, value.block).as_json hash[name] = result if result end end