diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index f7e7b435e..25d508481 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -112,19 +112,26 @@ def self.attributes(*attrs) # attributes :id, :recent_edits # attribute :name, key: :title # + # attribute :full_name do + # "#{object.first_name} #{object.last_name}" + # end + # # def recent_edits # object.edits.last(5) # end - def self.attribute(attr, options = {}) + def self.attribute(attr, options = {}, &block) key = options.fetch(:key, attr) _attributes_keys[attr] = { key: key } if key != attr - _attributes << key unless _attributes.include?(key) - serialized_attributes[key] = ->(object) { object.read_attribute_for_serialization(attr) } + if block_given? + serialized_attributes[key] = ->(instance) { instance.instance_eval(&block) } + else + serialized_attributes[key] = ->(instance) { instance.object.read_attribute_for_serialization(attr) } + end ActiveModelSerializers.silence_warnings do define_method key do - serialized_attributes[key].call(object) + serialized_attributes[key].call(self) end unless method_defined?(key) || _fragmented.respond_to?(attr) end end diff --git a/test/serializers/attribute_test.rb b/test/serializers/attribute_test.rb index 99452e530..e1368c27e 100644 --- a/test/serializers/attribute_test.rb +++ b/test/serializers/attribute_test.rb @@ -71,6 +71,21 @@ def id assert_equal('custom', hash[:blog][:id]) end + + PostWithVirtualAttribute = Class.new(::Model) + class PostWithVirtualAttributeSerializer < ActiveModel::Serializer + attribute :name do + "#{object.first_name} #{object.last_name}" + end + end + + def test_virtual_attribute_block + post = PostWithVirtualAttribute.new(first_name: 'Lucas', last_name: 'Hosseini') + hash = serializable(post).serializable_hash + expected = { name: 'Lucas Hosseini' } + + assert_equal(expected, hash) + end end end end