ruby-grape / ruby-grape/grape-entity
Grape::Entity#as_json does not return a recursive set of hashes.
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 729
- Forks
- 154
- PR merge metrics
- No merged PRs in 30d
Description
Given: A Grape::Entity that exposes another Grape::Entity
Expected: When calling .as_json (or serializable_hash) it should recursively convert all objects to hashes
Actual: Only the top level is converted, nested entities remain as: Grape::Entity::Exposure::NestingExposure::OutputBuilder
Discussed tangentially in: #39, #299, #313
The reason why perhaps this isn't more of an issue is that .to_json works correctly because that returns output from MultiJson: https://github.com/ruby-grape/grape-entity/blob/675d3c0e20dfc1d6cf6f5ba5b46741bd404c8be7/lib/grape_entity/entity.rb#L560-L563
Indeed, .as_json is just an alias for serializable_hash which is what isn't properly recursive. https://github.com/ruby-grape/grape-entity/blob/675d3c0e20dfc1d6cf6f5ba5b46741bd404c8be7/lib/grape_entity/entity.rb#L558
This is easily reproducible:
class TestCompany
attr_accessor :domain
end
class TestUser
attr_accessor :name
attr_accessor :company
end
class TestCompanyEntity < Grape::Entity
expose :domain
end
class TestUserEntity < Grape::Entity
expose :name
expose :company, using: TestCompanyEntity
end
tc = TestCompany.new.tap{|tc| tc.domain = "https://example.com" }
tu = TestUser.new.tap{|tu| tu.name = "John"}
tu.company = tc
tue = TestUserEntity.new(tu)
[26] pry(main)> tue.serializable_hash
=> {:name=>"John", :company=>{:domain=>"https://example.com"}}
[27] pry(main)> tue.serializable_hash.deep_stringify_keys
=> {"name"=>"John", "company"=>{:domain=>"https://example.com"}} # notice :domain is still a symbol
[28] pry(main)> tue.serializable_hash[:company].class # that's because company isn't a hash despite kinda looking like one
=> Grape::Entity::Exposure::NestingExposure::OutputBuilder
A simple workaround is for developers is to send it through JSON dump/parse
JSON.parse(JSON.dump(tue.serializable_hash))
But this seems unnecessary work and would be nice if this gem implemented recursive output at a higher level than just .to_json which gives us a string not a hash.
PS. Thank you to everyone who has worked on this gem! ❤️
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lib/grape_entity/entity.rb around the serializable_hash/as_json definition and the to_json implementation linked in the issue. Reproduce the nested TestUserEntity example, then verify that serializable_hash recursively returns ordinary hashes, including nested entity values, rather than OutputBuilder objects.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 50/100