-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
:only option for filtering #67
Comments
I'm hesitant to include complex hash-based configuration and options. In my opinion that's an anti-pattern in Rails, not a feature. In Oat a serializer is the unit that encapsulates a group of properties. Would it not be possible to use separate serializer classes? For example MiniUserSerializer.new(current_user, context) |
Thanks for responding! Well, my use case is really less concerned with the properties, but more with the entities... sometimes I need a user, sometimes a user with his posts, sometimes a user, her posts and the tags of those posts. Writing a new serializer for each case seems not very DRY... |
I think I don't agree with that definition of DRY. I find it cleaner, more deterministic and easier to test to just have separate classes that do one thing each, instead of one class that does all sort of things depending on deeply nested options. With Oat I wanted to get away from the complexity that comes with that kind of approach. Oat's As I see it, there are other options: Multiple serializersYou can have specific serializers that expose the attributes you want for each case. class FullUserSerializer < Oat::Serializer
schema do
type 'user'
properties do |props|
props.name item.name
# etc...
end
entities :friends, item.friends, MiniUserSerializer
end
end class MiniUserSerializer < Oat::Serializer
schema do
type 'user'
map_properties :name, :email, :id
end
end Use one serializer in combination with presentersYou can wrap your models in objects that expose an API that your serializers understand. class FullUserPresenter < SimpleDelegator
def include_friends?
true
end
end
class MiniUserPresenter < SimpleDelegator
def include_friends?
false
end
end Then your UserSerializer can rely on the class UserSerializer < Oat::Serializer
schema do
type 'user'
properties do |props|
props.name item.name
# etc
end
# Here we use the presenter API
if item.include_friends?
entities :friends, present_friends(item.friends), UserSerializer
end
end
private
def present_friends(friends)
friends.map{|f| MiniUserPresenter.new(f) }
end
end Finally, you instantiate the serializer passing the right presenter serializer = UserSerializer.new(MiniUserPresenter.new(user), context) ...The first option gives you simple classes with little variance. Easy to test and understand. But with some duplication. The second option gives you one class that does everything (less duplication) relying on presenters with well-defined APIs (which are testable) instead of hashes with a potentially unbounded number of options and permutations. |
The second options (with the presenters) is intriguing. However, it's still hard to specify what attributes to include for the nested resource (i.e. friends). I guess I'll have to write a special serializer for that case after all. Just thought this would be a quite common need... |
The nested resources can use one of the two options, too. Using a separate serializer: entities :friends, item.friends, NestedFriendSerializer Using the presenter approach and the same serializer entities :friends, present_friends(item.friends), UserSerializer
def present_friends(friends)
friends.map{|friend| FriendPresenter.new(friend) }
end Note that you can also write a custom base serializer that dries this up a bit for you. class MySerializer < Oat::Serializer
adapter Oat::Adapters::HAL # or whatever
private
# This is your own DSL
def friends(friends)
if item.include_friends?
presented_friends = friends.map{|f| FriendPresenter.new(f) }
entities :friends, presented_friends, self.class
end
end
end So then your UserSerializer can be class UserSerializer < MySerializer
schema do
# ... etc
friends item.friends
end
end More on sub-classing here. |
Thanks for your explanations! Looks I can get pretty far with this approach. |
It would be great if we could override the default props somehow, with the
:only
options familiar from Rails, like:Or is there a better way to achieve that kind of flexibility?
(an additional
:include
option could also be added, but seems harder to implement since you'd have to specify how to render the additional properties...)The text was updated successfully, but these errors were encountered: