Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ gemspec
gem "rexml", ">= 3.3.6"

group :development, :test do
gem "activejob", ">= 7.0", require: false
gem "debug"
gem "rake", "~> 13.0"
gem "rspec", "~> 3.0"
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ GEM
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (7.1.3.4)
activesupport (= 7.1.3.4)
globalid (>= 0.3.6)
activemodel (7.1.3.4)
activesupport (= 7.1.3.4)
activesupport (7.1.3.4)
Expand Down Expand Up @@ -52,6 +55,8 @@ GEM
drb (2.2.1)
erb (5.0.1)
erubi (1.13.0)
globalid (1.2.1)
activesupport (>= 6.1)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
io-console (0.8.0)
Expand Down Expand Up @@ -151,6 +156,7 @@ PLATFORMS
x86_64-linux

DEPENDENCIES
activejob (>= 7.0)
activemodel-entity!
debug
rake (~> 13.0)
Expand Down
3 changes: 3 additions & 0 deletions lib/active_model/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
require_relative "entity/validations/validates_nested"
require_relative "entity/pattern_matcheable"

# Load Railtie if Rails is defined
require_relative "entity/railtie" if defined?(Rails::Railtie)

module ActiveModel
# Main module providing all neccesary includes to bring missing functionality to ActiveModel instances.
module Entity
Expand Down
28 changes: 28 additions & 0 deletions lib/active_model/entity/active_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

# This file is only loaded when explicitly required or when Rails/ActiveJob is present
# It provides ActiveJob serialization support for ActiveModel::Entity objects

if defined?(ActiveJob)
module ActiveJob
module Serializers
# Handles serialization of all ActiveModel::Entity classes.
class ActiveModelSerializer < ActiveJob::Serializers::ObjectSerializer
def serialize?(argument)
argument.is_a?(ActiveModel::Entity)
end

def serialize(argument)
super(
"type" => argument.class.name,
"json" => argument.class.represent(argument),
)
end

def deserialize(hash)
hash["type"].constantize.from_json(hash["json"])
end
end
end
end
end
18 changes: 18 additions & 0 deletions lib/active_model/entity/railtie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module ActiveModel
module Entity
# Railtie to integrate with Rails and ActiveJob
class Railtie < Rails::Railtie
initializer "activemodel_entity.configure_active_job_serializer" do
require "active_model/entity/active_job"

if defined?(ActiveJob::Serializers::ActiveModelSerializer)
Rails.application.config.to_prepare do
Rails.application.config.active_job.custom_serializers << ActiveJob::Serializers::ActiveModelSerializer

Copilot AI Jul 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent duplicate registrations on each to_prepare run (e.g., in development reloads), guard this with an inclusion check, e.g.: unless config.active_job.custom_serializers.include?(...).

Suggested change
Rails.application.config.active_job.custom_serializers << ActiveJob::Serializers::ActiveModelSerializer
unless Rails.application.config.active_job.custom_serializers.include?(ActiveJob::Serializers::ActiveModelSerializer)
Rails.application.config.active_job.custom_serializers << ActiveJob::Serializers::ActiveModelSerializer
end

Copilot uses AI. Check for mistakes.
end
end
end
end
end
end
30 changes: 30 additions & 0 deletions spec/active_model/entity/active_job_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

require "spec_helper"

require "active_job"
require "active_model/entity/active_job"
require "active_job/arguments"

ActiveJob::Serializers.add_serializers(ActiveJob::Serializers::ActiveModelSerializer)

RSpec.describe ActiveJob::Serializers::ActiveModelSerializer do
subject(:entity) { klass.new(text: "hello", number: 1) }

let(:klass) do
Class.new do
include ActiveModel::Entity

attribute :text, :string
attribute :number, :integer
end
end

before do
stub_const("MyClass", klass)
end

it "serializes things back and forth" do
expect(ActiveJob::Arguments.deserialize(ActiveJob::Arguments.serialize([entity]))).to eq([entity])
end
end