Skip to content
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

Property options are ignored for JSON::Hash #215

Open
Envek opened this issue Mar 28, 2017 · 3 comments
Open

Property options are ignored for JSON::Hash #215

Envek opened this issue Mar 28, 2017 · 3 comments

Comments

@Envek
Copy link

Envek commented Mar 28, 2017

This doesn't work:

require 'representable'
require 'representable/json/hash'
require 'base64'

class FooRepresenterHash < Representable::Decorator
  include Representable::JSON::Hash

  property :binary1, getter:        proc { |represented:, **| represented['binary1'] && Base64.strict_encode64(represented['binary1']) }
  property :binary2, render_filter: proc { |input, **| input && Base64.strict_encode64(input) }
  property :binary3, exec_context:  :decorator

  def binary3
    represented['binary3'] && Base64.strict_encode64(represented['binary3'])
  end
end

puts FooRepresenterHash.new({'binary1' => 'b1', 'binary2' => 'b2', 'binary3' => 'b3'}).to_json
# => {"binary1":"b1","binary2":"b2","binary3":"b3"}

Neither getter, filter, nor method are being called at all.

But if replace JSON::Hash to just JSON (and wrap hash into OpenStruct) it works as expected:

require 'representable'
require 'ostruct'
require 'base64'

class FooRepresenter < Representable::Decorator
  include Representable::JSON

  property :binary1, getter:        lambda { |represented:, **| represented.binary1 && Base64.strict_encode64(represented.binary1) }
  property :binary2, render_filter: lambda { |input, **| input && Base64.strict_encode64(input) }
  property :binary3, exec_context:  :decorator

  def binary3
    represented.binary3 && Base64.strict_encode64(represented.binary3)
  end
end

puts FooRepresenter.new(OpenStruct.new({'binary1' => 'b1', 'binary2' => 'b2', 'binary3' => 'b3'})).to_json
# => {"binary1":"YjE=","binary2":"YjI=","binary3":"YjM="}
@stevenvegt
Copy link

I ran into this as well. The address field on our patient model is stored as a JSON field in MySQL. Rails converts these into a Hash.
Internally we use snake_case property names, our API is defined in camelcase.

# patient_representer.rb

require 'roar/decorator'
require 'roar/json'

class PatientRepresenter < Roar::Decorator
  include Roar::JSON

  defaults do |name, options|
    { as: name.to_s.camelize(:lower).to_sym }
  end

  property :id
  property :first_name
  ...
  property :address,
    decorator: AddressRepresenter
# address_representer.rb

require 'roar/decorator'
require 'roar/json/hash'

class AddressRepresenter < Roar::Decorator
  include Roar::JSON::Hash

  defaults do |name, options|
    { as: name.to_s.camelize(:lower).to_sym }
  end

  property :street_name
  property :house_number
  property :postal_code
  property :city
end

Representing a patient works, but the address properties are still represented in snake_case

@apotonick
Copy link
Member

I am pretty sure that defaults are not propagated into nested representers. It would make sense here, but could also be problematic in other cases, so maybe we need an option like the following?

defaults inherit: true do
  # ..
end

@stevenvegt
Copy link

I can understand that defaults are not propagated into nested representers but in my example I have a separate defaults block in AddressRepresenter. Are these defaults supposed to be ignored in a nested context?

Adding the inheritable options sounds good! Just to be clear, are you proposing to add the inherit option to the defaults of the parent (patient) or on the embedded resource (address)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants