Fix Time serialization regression from dropping MultiJson#404
Fix Time serialization regression from dropping MultiJson#404
Conversation
Danger ReportNo issues found. |
There was a problem hiding this comment.
Pull request overview
Fixes a regression introduced when switching from MultiJson.dump to JSON.dump by restoring ActiveSupport-aware JSON serialization for Time values in Grape::Entity#to_json.
Changes:
- Switch
Entity#to_jsonto serialize viaserializable_hash(...).to_jsonto re-enable ActiveSupport’sas_jsonchain (restoring ISO 8601Timeoutput). - Remove the now-unused
Grape::Entity::Jsonshim and its spec. - Add specs asserting
Timeserialization usesas_json, including for nested exposures.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| spec/grape_entity/json_spec.rb | Removes spec for the deleted Grape::Entity::Json constant. |
| spec/grape_entity/entity_spec.rb | Adds regression coverage for Time serialization (top-level + nested exposures). |
| lib/grape_entity/json.rb | Removes the Grape::Entity::Json backend-selection shim. |
| lib/grape_entity/entity.rb | Updates #to_json implementation to call to_json on the serializable output (ActiveSupport-aware). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
JSON.dump bypasses ActiveSupport's Hash#to_json override, causing
Time values to serialize via Time#to_s ("2026-04-16 10:55:10 UTC")
instead of ActiveSupport's as_json ("2026-04-16T10:55:10.597Z").
Replace Json.dump with Hash#to_json which properly delegates through
ActiveSupport and remove the now-unused Grape::Entity::Json constant.
Fixes #403
374a021 to
09ed8be
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes a serialization regression introduced when switching JSON backends by ensuring Time (and other ActiveSupport-enhanced types) are serialized through ActiveSupport’s as_json chain again, restoring ISO 8601 timestamp output for API consumers.
Changes:
- Switch
Grape::Entity#to_jsonto serialize viaserializable_hash(...).to_json(ActiveSupport-aware) instead ofMultiJson.dump. - Remove the
multi_jsonruntime dependency from the gemspec. - Document the fix and dependency removal in the changelog.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| lib/grape_entity/entity.rb | Restores ActiveSupport-aware JSON serialization by using Hash#to_json on the computed serializable output. |
| grape-entity.gemspec | Drops the multi_json dependency now that it’s no longer used. |
| CHANGELOG.md | Notes the regression fix and dependency removal in the Unreleased fixes section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Version 1.0.3 introduced a silent breaking change for all API consumers:
Timefields switched from ISO 8601 format ("2026-04-16T10:55:10.597Z") to Ruby's defaultTime#to_sformat ("2026-04-16 10:55:10 UTC"). This breaks any client parsing timestamps from the API.What happened
PR #385 replaced
MultiJson.dumpwithJSON.dumpinEntity#to_jsonto drop themulti_jsondependency. While the intent was correct,JSON.dumpandMultiJson.dumpbehave differently when ActiveSupport is present:MultiJson.dump(hash)internally callsHash#to_json, which ActiveSupport overrides to runas_jsonrecursively on all values — givingTimethe ISO 8601 representation.JSON.dump(hash)goes directly to Ruby's C extension JSON generator, bypassing ActiveSupport'sHash#to_jsonoverride entirely — soTimefalls back toTime#to_s.Since ActiveSupport is a runtime dependency of grape-entity, every user is affected.
An additional problem noted by @stevenou: the intermediate
Grape::Entity::Jsonconstant useddefined?(::MultiJson)at require time to decide which backend to use. For apps withgem "multi_json", require: false, MultiJson wasn't loaded yet at that point, so it always fell back to::JSONregardless — making the MultiJson detection dead code in practice.How this fix works
Replaces
Grape::Entity::Json.dump(serializable_hash(options))withserializable_hash(options).to_json.Hash#to_jsonis the method ActiveSupport overrides. This single change resolves all reported problems:Hash#to_jsongoes through ActiveSupport'sas_jsonchain, restoring ISO 8601 output forTimeand any other type with anas_jsonoverride.OutputBuilder(aSimpleDelegatorwrapping a Hash) properly delegates.to_jsonto the underlying Hash.require: falsescenarios are irrelevant.The now-unused
Grape::Entity::Jsonconstant andgrape_entity/json.rbare removed.Fixes #403