Sitelet https://github.com/jsonapi-serializer/jsonapi-serializer/pull/102/files
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ the block to only receive one argument.

### Conditional Attributes

Conditional attributes can be defined by passing a Proc to the `if` key on the `attribute` method. Return `true` if the attribute should be serialized, and `false` if not. The record and any params passed to the serializer are available inside the Proc as the first and second parameters, respectively.
Conditional attributes can be defined by passing a Proc or a symbolized name of a method defined in the serializer to the `if` key on the `attribute` method. Return `true` if the attribute should be serialized, and `false` if not. The record and any params passed to the serializer are available inside the Proc as the first and second parameters, respectively.

```ruby
class MovieSerializer
Expand All @@ -469,13 +469,27 @@ class MovieSerializer
# The director will be serialized only if the :admin key of params is true
params && params[:admin] == true
}

attribute :country, if: :show_country
attribute :rating, if: :show_rating

def show_country(_object, params)
# The country will be serialized only if the :admin key of params is true
params.try(:admin) == true
end

def show_rating(object)
# The rating will be shown only if it's higher than 2
object.rating > 2
end
end

# ...
current_user = User.find(cookies[:current_user_id])
serializer = MovieSerializer.new(movie, { params: { admin: current_user.admin? }})
serializer.serializable_hash
```
The same stands for links and `link` method.

### Conditional Relationships

Expand Down
6 changes: 4 additions & 2 deletions lib/fast_jsonapi/object_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ def attributes(*attributes_list, &block)
attributes_to_serialize[key] = Attribute.new(
key: key,
method: block || method_name,
options: options
options: options,
serializer: self
)
end
end
Expand Down Expand Up @@ -330,7 +331,8 @@ def link(*params, &block)
data_links[key] = Link.new(
key: key,
method: block || link_method_name,
options: options
options: options,
serializer: self
)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/fast_jsonapi/relationship.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def add_links_hash(record, params, output_hash)
record.public_send(links)
else
links.each_with_object({}) do |(key, method), hash|
Link.new(key: key, method: method).serialize(record, params, hash)
Link.new(key: key, method: method, serializer: serializer).serialize(record, params, hash)
end
end
end
Expand Down
20 changes: 12 additions & 8 deletions lib/fast_jsonapi/scalar.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module FastJsonapi
class Scalar
attr_reader :key, :method, :conditional_proc
attr_reader :key, :method, :conditional, :serializer

def initialize(key:, method:, options: {})
def initialize(key:, method:, options: {}, serializer:)
@key = key
@method = method
@conditional_proc = options[:if]
@conditional = options[:if]
@serializer = serializer
end

def serialize(record, serialization_params, output_hash)
Expand All @@ -19,11 +20,14 @@ def serialize(record, serialization_params, output_hash)
end

def conditionally_allowed?(record, serialization_params)
if conditional_proc.present?
FastJsonapi.call_proc(conditional_proc, record, serialization_params)
else
true
end
return true unless conditional.present?

conditional_proc = if conditional.is_a? Symbol
serializer.new(record, serialization_params).method(conditional).to_proc
else
conditional
end
FastJsonapi.call_proc(conditional_proc, record, serialization_params)
end
end
end
14 changes: 13 additions & 1 deletion spec/fixtures/actor.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
require 'active_support/cache'

class Actor < User
attr_accessor :movies, :movie_ids
attr_accessor :movies, :movie_ids, :age, :birthplace, :show_birthplace

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need :show_birthplace in the list of attributes, let's just keep it as a method... What do you think?


def self.fake(id = nil)
faked = super(id)
faked.movies = []
faked.movie_ids = []
faked.age = rand(99)
faked.birthplace = FFaker::Address.city
faked
end

Expand All @@ -21,6 +23,8 @@ class ActorSerializer < UserSerializer
set_type :actor

attribute :email, if: ->(_object, params) { params[:conditionals_off].nil? }
attribute :age, if: :symbol_conditionals_off
attribute :birthplace, if: :show_birthplace

has_many(
:played_movies,
Expand All @@ -30,6 +34,14 @@ class ActorSerializer < UserSerializer
) do |object|
object.movies
end

def symbol_conditionals_off(_object, params)
params[:symbol_conditionals_off].nil?
end

def show_birthplace(object)
object.show_birthplace
end

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need both conditionals here. I think having just one (for ex. age) is more than enough since the interface of the conditional method will always provide the object and the params (based on FastJsonapi#call_proc) as the arguments. So it's up to the end-user to decide what to do with it.

Let me know if I'm not missing anything here...

end

class CamelCaseActorSerializer
Expand Down
26 changes: 22 additions & 4 deletions spec/integration/attributes_fields_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
expect(serialized['data']).to have_type('actor')

expect(serialized['data'])
.to have_jsonapi_attributes('first_name', 'last_name', 'email').exactly
.to have_jsonapi_attributes('first_name', 'last_name', 'email', 'age').exactly
expect(serialized['data']).to have_attribute('first_name')
.with_value(actor.first_name)
expect(serialized['data']).to have_attribute('last_name')
Expand All @@ -33,10 +33,28 @@
end

context 'with `if` conditions' do
let(:params) { { params: { conditionals_off: 'yes' } } }
context 'when condition is a proc' do
let(:params) { { params: { conditionals_off: 'yes' } } }

it do
expect(serialized['data']).not_to have_attribute('email')
it do
expect(serialized['data']).not_to have_attribute('email')
end

context 'when condition is a symbol and method accepts params' do
let(:params) { { params: { symbol_conditionals_off: 'yes' } } }

it do
expect(serialized['data']).not_to have_attribute('age')
end
end

context 'when condition is a symbol and method accepts only record' do
before { actor.show_birthplace = true }

it do
expect(serialized['data']).to have_attribute('birthplace')
end
end
end
end

Expand Down