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