active_model_serializers icon indicating copy to clipboard operation
active_model_serializers copied to clipboard

Execution context when using a block for `has_one` vs `attribute`

Open marcrohloff opened this issue 4 years ago • 4 comments
trafficstars

Expected behavior vs actual behavior

Expected the execution context (self) to be the same when using something like has_one :something do as it is with attribute :something do. Maybe this is by design but it seems unusual.

This discovery came about as a result of trying to access instance_options which seems to not be possible (see Additional information)

Steps to reproduce

Given

class TestSerializer < ActiveModel::Serializer
  attribute :attr do 
    self.class.name
  end
  has_one :child do
    { class: self.class.name }
  end
end

test output is

> TestSerializer.new(self).as_json
=> {:attr=>"TestSerializer", :child=>{:class=>"ActiveModel::Serializer::HasOneReflection"}}

Environment

ActiveModelSerializers Version: v0.10.10

Output of ruby -e "puts RUBY_DESCRIPTION": ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]

OS Type & Version: Linux Mint 20.1

Integrated application and version (e.g., Rails, Grape, etc): Rails 6.0

Additional helpful information

The following syntax doesn't work either as instance_options is protected

  has_one :h do |serializer|
    if serializer.instance_options[:include_all]
    ... 
  end

marcrohloff avatar Mar 12 '21 21:03 marcrohloff

Thanks for your report. What are you trying to do?

bf4 avatar Mar 16 '21 05:03 bf4

In this case I was trying to access the instance_options, but it is confusing that the methods act differently

marcrohloff avatar Mar 16 '21 05:03 marcrohloff

well, attributes are on the object so don't need to be handled by a reflection like relations do.

I had thought you could yield the serializer instance to get access to that stuff. it's been a while since I've been in the code and I'm assuming you've read through the docs and code at this point, so I might be wrong.

bf4 avatar Mar 16 '21 13:03 bf4

The serializer is yielded but you can't access instance_options since its protected.

Some options I can think of are:

  • Expose instance_options in the reflection (this is already done for scope and object)
  • Make instance_options public on the serializer
  • Have the reflection delegate to serializer so you get the best of both worlds (including methods you define yourself on the serializer)

fwiw, the work-around is just to use a method instead of a block

marcrohloff avatar Mar 16 '21 16:03 marcrohloff