简体   繁体   中英

Usage of as_json and dynamic method

I have an simple class (without Rails)

class Tax

  attr_reader :guest_age

  def initialize(guest_age)
    @guest_age = guest_age
  end

  def amount
    0
  end

end

This object has an "amount" custom method and I want to include the amount result in the json when I do this : tax.as_json(methods: :amount)

But this is not working, this return only the object with variables.

What I'm getting now :

{ "guest_age": 18 }

What I am expecting is :

{ "guest_age": 18, "amount": 0 }

See https://apidock.com/rails/ActiveModel/Serializers/JSON/as_json

Note :

I want to keep this object without active record library dependency.

Tested with Rails 5.2.2, this is the source of as_json :

def as_json(options = nil) #:nodoc:
  if respond_to?(:to_hash)
    to_hash.as_json(options)
  else
    instance_values.as_json(options)
  end
end

Which means that if you implement a to_hash method in your class, your as_json call will work the way you wish:

class Tax

  attr_reader :guest_age

  def initialize(guest_age)
    @guest_age = guest_age
  end

  def amount
    0
  end

  def to_hash
    instance_values.merge(amount: amount)
  end
end

And...

Tax.new(1).as_json
# => {"guest_age"=>1, "amount"=>0}

This will include the amount always though, there does not seem to be an easy way around that.

It can work differently though, you need to explicitly throw away the amount :

Tax.new(1).as_json(except: :amount)
# => {"guest_age"=>1}

Or explicitly specify the attributes you wish to be serialized:

Tax.new(1).as_json(only: "guest_age")
# => {"guest_age"=>1}

The methods option that you'd like to use seems to be strictly tied to ActiveRecord.

Can you define a custom method in your class?

  def to_h
    {guest_age: @guest_age, amount: amount}
  end

So you can call:

tax = Tax.new(18)
p tax.to_h
#=> {:guest_age=>18, :amount=>0}

Or

require 'json'
puts tax.to_h.to_json
#=> {"guest_age":18,"amount":0}

the method option works for active model object.

class Tax

  include ActiveModel::Serialization
  include ActiveModel::Serializers::JSON

  attr_accessor :guest_age

  def initialize(guest_age)
    @guest_age = guest_age
  end

  def attributes
    {'guest_age' => nil}
  end

  def amount
    0
  end

end

code like this should work, for more info see the source code.

https://github.com/rails/rails/blob/master/activemodel/lib/active_model/serialization.rb

https://github.com/rails/rails/blob/master/activemodel/lib/active_model/serializers/json.rb

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM