Skip to content

Commit

Permalink
String/Lambda support for conditional attributes/associations
Browse files Browse the repository at this point in the history
  • Loading branch information
mtsmfm committed Apr 21, 2016
1 parent f0fa743 commit c1fd222
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Breaking changes:
- [#1574](https://github.com/rails-api/active_model_serializers/pull/1574) Default key case for the JsonApi adapter changed to dashed. (@remear)

Features:
- [#1699](https://github.com/rails-api/active_model_serializers/pull/1699) String/Lambda support for conditional attributes/associations (@mtsmfm)
- [#1687](https://github.com/rails-api/active_model_serializers/pull/1687) Only calculate `_cache_digest` (in `cache_key`) when `skip_digest` is false. (@bf4)
- [#1647](https://github.com/rails-api/active_model_serializers/pull/1647) Restrict usage of `serializable_hash` options
to the ActiveModel::Serialization and ActiveModel::Serializers::JSON interface. (@bf4)
Expand Down
3 changes: 3 additions & 0 deletions docs/general/serializers.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ end

```ruby
has_one :blog, if: :show_blog?
# you can also use a string or lambda
# has_one :blog, if: 'scope.admin'
# has_one :blog, if: -> (serializer) { serializer.scope.admin? }

def show_blog?
scope.admin?
Expand Down
17 changes: 15 additions & 2 deletions lib/active_model/serializer/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,29 @@ def value(serializer)
def excluded?(serializer)
case condition_type
when :if
!serializer.public_send(condition)
!evaluate_condition(serializer)
when :unless
serializer.public_send(condition)
evaluate_condition(serializer)
else
false
end
end

private

def evaluate_condition(serializer)
case condition
when Symbol
serializer.public_send(condition)
when String
serializer.instance_eval(condition)
when Proc
condition.call(serializer)
else
fail ArgumentError
end
end

def condition_type
@condition_type ||=
if options.key?(:if)
Expand Down
32 changes: 31 additions & 1 deletion test/serializers/associations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def test_associations_namespaced_resources
end
end

def test_conditional_associations
def test_symbol_conditional_associations
serializer = Class.new(ActiveModel::Serializer) do
belongs_to :if_assoc_included, if: :true
belongs_to :if_assoc_excluded, if: :false
Expand All @@ -261,6 +261,36 @@ def false

assert_equal(expected, hash)
end

def test_string_conditional_associations
serializer = Class.new(ActiveModel::Serializer) do
belongs_to :if_assoc_included, if: 'object.true'
belongs_to :if_assoc_excluded, if: 'object.false'
belongs_to :unless_assoc_included, unless: 'object.false'
belongs_to :unless_assoc_excluded, unless: 'object.true'
end

model = ::Model.new(true: true, false: false)
hash = serializable(model, serializer: serializer).serializable_hash
expected = { if_assoc_included: nil, unless_assoc_included: nil }

assert_equal(expected, hash)
end

def test_lambda_conditional_associations
serializer = Class.new(ActiveModel::Serializer) do
belongs_to :if_assoc_included, if: -> (s) { s.object.true }
belongs_to :if_assoc_excluded, if: -> (s) { s.object.false }
belongs_to :unless_assoc_included, unless: -> (s) { s.object.false }
belongs_to :unless_assoc_excluded, unless: -> (s) { s.object.true }
end

model = ::Model.new(true: true, false: false)
hash = serializable(model, serializer: serializer).serializable_hash
expected = { if_assoc_included: nil, unless_assoc_included: nil }

assert_equal(expected, hash)
end
end
end
end
Expand Down
32 changes: 31 additions & 1 deletion test/serializers/attribute_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def test_virtual_attribute_block
assert_equal(expected, hash)
end

def test_conditional_attributes
def test_symbol_conditional_attributes
serializer = Class.new(ActiveModel::Serializer) do
attribute :if_attribute_included, if: :true
attribute :if_attribute_excluded, if: :false
Expand All @@ -118,6 +118,36 @@ def false

assert_equal(expected, hash)
end

def test_string_conditional_attributes
serializer = Class.new(ActiveModel::Serializer) do
attribute :if_attribute_included, if: 'object.true'
attribute :if_attribute_excluded, if: 'object.false'
attribute :unless_attribute_included, unless: 'object.false'
attribute :unless_attribute_excluded, unless: 'object.true'
end

model = ::Model.new(true: true, false: false)
hash = serializable(model, serializer: serializer).serializable_hash
expected = { if_attribute_included: nil, unless_attribute_included: nil }

assert_equal(expected, hash)
end

def test_lambda_conditional_attributes
serializer = Class.new(ActiveModel::Serializer) do
attribute :if_attribute_included, if: -> (s) { s.object.true }
attribute :if_attribute_excluded, if: -> (s) { s.object.false }
attribute :unless_attribute_included, unless: -> (s) { s.object.false }
attribute :unless_attribute_excluded, unless: -> (s) { s.object.true }
end

model = ::Model.new(true: true, false: false)
hash = serializable(model, serializer: serializer).serializable_hash
expected = { if_attribute_included: nil, unless_attribute_included: nil }

assert_equal(expected, hash)
end
end
end
end

0 comments on commit c1fd222

Please sign in to comment.