diff --git a/lib/active_model/serializer/attribute.rb b/lib/active_model/serializer/attribute.rb index 23d2b3d6..d3e006fa 100644 --- a/lib/active_model/serializer/attribute.rb +++ b/lib/active_model/serializer/attribute.rb @@ -1,40 +1,25 @@ +require 'active_model/serializer/field' + module ActiveModel class Serializer - Attribute = Struct.new(:name, :options, :block) do - def value(serializer) - if block - serializer.instance_eval(&block) - else - serializer.read_attribute_for_serialization(name) - end - end - - def included?(serializer) - case condition - when :if - serializer.public_send(condition) - when :unless - !serializer.public_send(condition) - else - true - end - end - - private - - def condition_type - if options.key?(:if) - :if - elsif options.key?(:unless) - :unless - else - :none - end - end - - def condition - options[condition_type] - end + # Holds all the meta-data about an attribute as it was specified in the + # ActiveModel::Serializer class. + # + # @example + # class PostSerializer < ActiveModel::Serializer + # attribute :content + # attribute :name, key: :title + # attribute :email, key: :author_email, if: :user_logged_in? + # attribute :preview do + # truncate(object.content) + # end + # + # def user_logged_in? + # current_user.logged_in? + # end + # end + # + class Attribute < Field end end end diff --git a/lib/active_model/serializer/field.rb b/lib/active_model/serializer/field.rb new file mode 100644 index 00000000..79f97e7b --- /dev/null +++ b/lib/active_model/serializer/field.rb @@ -0,0 +1,55 @@ +module ActiveModel + class Serializer + # Holds all the meta-data about a field (i.e. attribute or association) as it was + # specified in the ActiveModel::Serializer class. + # Notice that the field block is evaluated in the context of the serializer. + Field = Struct.new(:name, :options, :block) do + # Compute the actual value of a field for a given serializer instance. + # @param [Serializer] The serializer instance for which the value is computed. + # @return [Object] value + # + # @api private + # + def value(serializer) + if block + serializer.instance_eval(&block) + else + serializer.read_attribute_for_serialization(name) + end + end + + # Decide whether the field should be serialized by the given serializer instance. + # @param [Serializer] The serializer instance + # @return [Bool] + # + # @api private + # + def included?(serializer) + case condition + when :if + serializer.public_send(condition) + when :unless + !serializer.public_send(condition) + else + true + end + end + + private + + def condition_type + if options.key?(:if) + :if + elsif options.key?(:unless) + :unless + else + :none + end + end + + def condition + options[condition_type] + end + end + end +end diff --git a/lib/active_model/serializer/reflection.rb b/lib/active_model/serializer/reflection.rb index 484b95ae..c0287b64 100644 --- a/lib/active_model/serializer/reflection.rb +++ b/lib/active_model/serializer/reflection.rb @@ -1,18 +1,24 @@ +require 'active_model/serializer/field' + module ActiveModel class Serializer # Holds all the meta-data about an association as it was specified in the # ActiveModel::Serializer class. # # @example - # class PostSerializer < ActiveModel::Serializer + # class PostSerializer < ActiveModel::Serializer # has_one :author, serializer: AuthorSerializer # has_many :comments # has_many :comments, key: :last_comments do # object.comments.last(1) # end - # end + # has_many :secret_meta_data, if: :is_admin? + # + # def is_admin? + # current_user.admin? + # end + # end # - # Notice that the association block is evaluated in the context of the serializer. # Specifically, the association 'comments' is evaluated two different ways: # 1) as 'comments' and named 'comments'. # 2) as 'object.comments.last(1)' and named 'last_comments'. @@ -21,32 +27,13 @@ module ActiveModel # # [ # # HasOneReflection.new(:author, serializer: AuthorSerializer), # # HasManyReflection.new(:comments) + # # HasManyReflection.new(:comments, { key: :last_comments }, #) + # # HasManyReflection.new(:secret_meta_data, { if: :is_admin? }) # # ] # # So you can inspect reflections in your Adapters. # - Reflection = Struct.new(:name, :options, :block) do - # @api private - def value(instance) - if block - instance.instance_eval(&block) - else - instance.read_attribute_for_serialization(name) - end - end - - # @api private - def included?(serializer) - case condition_type - when :if - serializer.public_send(condition) - when :unless - !serializer.public_send(condition) - else - true - end - end - + class Reflection < Field # Build association. This method is used internally to # build serializer's association by its reflection. # @@ -91,20 +78,6 @@ module ActiveModel private - def condition_type - if options.key?(:if) - :if - elsif options.key?(:unless) - :unless - else - :none - end - end - - def condition - options[condition_type] - end - def serializer_options(subject, parent_serializer_options, reflection_options) serializer = reflection_options.fetch(:serializer, nil)