-
Notifications
You must be signed in to change notification settings - Fork 361
Integrate with Active Record's .serialize
#420
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
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rafaelfranca
requested changes
Sep 10, 2025
Define `ActiveResource::Base.dump` and `ActiveResource::Base.load` to
support passing classes directly to [serialize][] as the `:coder`
option:
Writing to String columns
---
Encodes Active Resource instances into a string to be stored in the
database. Decodes strings read from the database into Active Resource
instances.
```ruby
class User < ActiveRecord::Base
serialize :person, coder: Person
end
class Person < ActiveResource::Base
schema do
attribute :name, :string
end
end
user = User.new
user.person = Person.new name: "Matz"
user.person_before_type_cast # => "{\"name\":\"Matz\"}"
```
Writing string values incorporates the Base.format:
```ruby
Person.format = :xml
user.person = Person.new name: "Matz"
user.person_before_type_cast # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?><person><name>Matz</name></person>"
```
Instances are loaded as persisted when decoded from data containing a
primary key value, and new records when missing a primary key value:
```ruby
user.person = Person.new
user.person.persisted? # => false
user.person = Person.find(1)
user.person.persisted? # => true
```
Writing to JSON and JSONB columns
---
```ruby
class User < ActiveRecord::Base
serialize :person, coder: ActiveResource::Coder.new(Person, :serializable_hash)
end
class Person < ActiveResource::Base
schema do
attribute :name, :string
end
end
user = User.new
user.person = Person.new name: "Matz"
user.person_before_type_cast # => {"name"=>"Matz"}
user.person.name # => "Matz"
```
The `ActiveResource::Coder` class
===
By default, `#dump` serializes the instance to a string value by
calling `ActiveResource::Base#encode`:
```ruby
user.person_before_type_cast # => "{\"name\":\"Matz\"}"
```
To customize serialization, pass the method name or a block as the second
argument:
```ruby
person = Person.new name: "Matz"
coder = ActiveResource::Coder.new(Person, :serializable_hash)
coder.dump(person) # => {"name"=>"Matz"}
coder = ActiveResource::Coder.new(Person) { |person| person.serializable_hash }
coder.dump(person) # => {"name"=>"Matz"}
```
[serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 25, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 25, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 25, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 25, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 25, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Improving the test coverage uncovered that the `Coder.load` implementation did not support inferring the correct `@persisted` value from payloads with root-level keys. For example, `{ "person": { "id": 1 } }` will not be inferred as persisted in the same way that `{ "id": 1 }` will. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. To resolve the `@persisted` value, call `Format.remove_root` to ensure that the payload consists of only attributes. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. The `Coder#load` implementation does not support inferring the correct `@persisted` value from payloads with root-level keys. For example, `{ "person": { "id": 1 } }` will not be inferred as persisted in the same way that `{ "id": 1 }` will. Proposal --- To resolve the `@persisted` value, call `Format.remove_root` to ensure that the payload consists of only attributes. [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. The `Coder#load` implementation does not support inferring the correct `@persisted` value from payloads with root-level keys. For example, `{ "person": { "id": 1 } }` will not be inferred as persisted in the same way that `{ "id": 1 }` will. Proposal --- To resolve the `@persisted` value, call `Format.remove_root` to ensure that the payload consists of only attributes. [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Improving the test coverage uncovered that the `Coder.load` implementation did not support inferring the correct `@persisted` value from payloads with root-level keys. For example, `{ "person": { "id": 1 } }` will not be inferred as persisted in the same way that `{ "id": 1 }` will. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. To resolve the `@persisted` value, call `Format.remove_root` to ensure that the payload consists of only attributes. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. The `Coder#load` implementation does not support inferring the correct `@persisted` value from payloads with root-level keys. For example, `{ "person": { "id": 1 } }` will not be inferred as persisted in the same way that `{ "id": 1 }` will. Proposal --- To resolve the `@persisted` value, call `Format.remove_root` to ensure that the payload consists of only attributes. [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Improving the test coverage uncovered that the `Coder.load` implementation did not support inferring the correct `@persisted` value from payloads with root-level keys. For example, `{ "person": { "id": 1 } }` will not be inferred as persisted in the same way that `{ "id": 1 }` will. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. To resolve the `@persisted` value, call `Format.remove_root` to ensure that the payload consists of only attributes. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. The intent was to integrate with the Active Record [.serialize][] method. Problem --- While the `Coder` class and `Serialization` module aim to comply with Active Record, there's still potential for that compatibility to drift of break without sufficient test coverage. Proposal --- This commit adds a test-only dependency on `activerecord` and `sqlite3` so that the serialization test coverage can include database-level reads and writes. The suite is configured to use the in-memory SQLite adapter so that there are no need for migrations or external database configuration. [rails#420]: rails#420 [.serialize]: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Sep 26, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Oct 1, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Oct 1, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Oct 2, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
seanpdoyle
added a commit
to seanpdoyle/activeresource
that referenced
this pull request
Oct 2, 2025
Follow-up to [rails#420][] Background --- The introduction of `ActiveResource::Base.coder` and the `ActiveResource::Coder` class added support for encoding and decoding instances of `Base`. However, collection-focused methods like `Base.where`, `Base.all`, and `Base.find(:all)` return `ActiveResource::Collection` instances. Problem --- While some collection instances are equivalent to `Array` instances, they are capable of being parsed into `Hash` values that include additional metadata (for example, pagination URLs, total counts, etc.). If applications were to dump results, there is a potential loss of that metadata. Proposal --- First, this commit modifies the `ActiveResource::Coder` class to accept a boolean `:collection` keyword to treat values as `ActiveResource::Collection` instances. Next, extend the `ActiveResource::Collection` class to retain the originally parsed values as a new `#original_parsed` attribute. It also defines the `#encode` method to rely on the resource class format for encoding. Additionally, extend the `ActiveResource::Serialization` module to also define a `.collection_coder` class attribute to serve as a convenience method for consumer to pass to `.serialize …, coder: …`: ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord serialize :people, coder: Person.collection_coder end ``` Like the instance-level coders, collection-level coders constructed with `collection: true` also accept an encoder proc to transform the value prior to dumping (for JSON/JSONB columns, for example): ```ruby class Person < ActiveResource::Base # … end class Team < ApplicationRecord # pass a to_proc-ready method name serialize :people, coder: ActiveResource::Coder.new(Person, :original_parsed, collection: true) # pass a block serialize :people, coder: ActiveResource::Coder.new(Person, collection: true) do |collection| collection.original_parsed end end ``` [rails#420]: rails#420
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Define
ActiveResource::Base.dumpandActiveResource::Base.loadto support passing classes directly to serialize as the:coderoption:Writing to String columns
Encodes Active Resource instances into a string to be stored in the database. Decodes strings read from the database into Active Resource instances.
Writing string values incorporates the Base.format:
Instances are loaded as persisted when decoded from data containing a primary key value, and new records when missing a primary key value:
Writing to JSON and JSONB columns
The
ActiveResource::CoderclassBy default,
#dumpserializes the instance to a string value by callingActiveResource::Base#encode:To customize serialization, pass the method name or a block as the second argument: