Skip to content

Representers: defaults block is lost in nested declarations #22

@carlthuringer

Description

@carlthuringer

Complete Description of Issue

Due to legacy design, we want to use the non-strict behavior for as: for property-names, allowing underscores.

Following the Documentation I implemented a representer with the default set to strict: false.

require "roar/json"
require "roar/json/json_api"

class RuleRepresenter < Roar::Decorator
  include Roar::JSON::JSONAPI.resource :rules

  defaults do |name, _|
    { as: JSONAPI::MemberName.call(name, strict: false) }
  end

  attributes do
    property :chain_id
    property :name
    property :event_type
  end
end

However, the output was hyphenated!

[{:id=>"1c9c618a-86ad-437f-b3dd-50dd5a3e290f", :attributes=>{:"chain-id"=>"072bb8ca-a7c7-4408-b5f1-831d7277f676", :"event-type"=>"transactions"}, :type=>"rules"}]

I was able to workaround by changing my Representer. I placed the defaults block inside of the attributes block.

require "roar/json"
require "roar/json/json_api"

class RuleRepresenter < Roar::Decorator
  include Roar::JSON::JSONAPI.resource :rules

  attributes do
    defaults do |name, _|
      { as: JSONAPI::MemberName.call(name, strict: false) }
    end

    property :chain_id
    property :name
    property :event_type
  end
end

Steps to reproduce

Create a representer which sets a defaults block like so:

defaults do |name, _|
  { as: JSONAPI::MemberName.call(name, strict: false) }
end

and has attributes

attributes do
  property :name
end

Expected behavior

The attributes should be allowed to pass the non-strict conversion and remain underscored.

Actual behavior

Attributes are hyphenated.

System configuration

Roar version: 1.1.0
Roar JSONAPI version: 0.0.3
Declarative version: 0.0.9

During research, I found many things I didn't understand. Please excuse my ignorance.

  • attributes -> Roar::JSON::JSONAPI::Declarative, sets the inherit: true property, presumably so you can have multiple attributes blocks and they merge together.
  • nested -> When a block is passed, the options[:_base] is set to Decorator.default_nested_class, which is just an base Representable::Decorator. At this point, self is actually still RuleRepresenter.
  • Several steps omitted...
  • Declarative::Definitions::Definition#add Called with attributes, options and the block. Here it extracts some properties, calls the _defaults pipeline, and then calls the nested builder with the _base, name, and block.
  • Declarative::Schema::DSL::NestedBuilder (proc) is called, wherein self is Declarative::Schema::DSL. No context anymore here, except what was provided in options. which is provided for that purpose. This proc begins with Class.new(options[:_base]), which extends the Representable::Decorator supplied above. Then a block is evaluated which adds the features from the options context, and finally the block is class_evald. The evaluation of feature with the Roar::JSON::JSONAPI::Defaults feature sets up @options with a fresh set, and the options[:_defaults] from the parent is not used here. There's no way to set the options. There's no way to access the @dynamic_options block of options[:_defaults] either. I can't determine if there's some means by which to merge without hacking too much further.

Now, if you were to change Roar::JSON::JSONAPI::Declarative to pass the private option _defaults, then those configurations would be available inside of Declarative::Definitions::Definition#add. However, getting it merged inside of Declarative::Schema::DSL::NestedBuilder is beyond me at this time.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions