From 430d08f18f4137c1b8aa69b24e1ae106c569afcd Mon Sep 17 00:00:00 2001 From: Alexander Senko Date: Tue, 6 Feb 2024 20:37:46 +0700 Subject: [PATCH] Improved integration with Global ID Implementing `Decorator.find` improves compatibility with Global ID and allows one to use decorated objects in jobs seamlessly. Resolves drapergem/draper#663. Improves drapergem/draper#817. --- README.md | 5 ++--- lib/draper/compatibility/global_id.rb | 14 +++++++++----- spec/dummy/spec/decorators/post_decorator_spec.rb | 9 +++++++++ spec/dummy/spec/jobs/publish_post_job_spec.rb | 4 +++- spec/dummy/spec/models/post_spec.rb | 7 ------- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8d400106..7fa2e016 100644 --- a/README.md +++ b/README.md @@ -672,9 +672,8 @@ you can include this module manually. [Active Job](http://edgeguides.rubyonrails.org/active_job_basics.html) allows you to pass ActiveRecord objects to background tasks directly and performs the necessary serialization and deserialization. In order to do this, arguments to a background job must implement [Global ID](https://github.com/rails/globalid). -Decorated objects implement Global ID by delegating to the object they are decorating. This means -you can pass decorated objects to background jobs, however, the object won't be decorated when it is -deserialized. +Decorators implement Global ID. +This means you can pass decorated objects to background jobs, and get them just as decorated when deserialized. ## Contributors diff --git a/lib/draper/compatibility/global_id.rb b/lib/draper/compatibility/global_id.rb index 271be65f..fb8e8da9 100644 --- a/lib/draper/compatibility/global_id.rb +++ b/lib/draper/compatibility/global_id.rb @@ -5,17 +5,21 @@ module Compatibility # and deserialization. In order to do this, arguments to a background job must implement # [Global ID](https://github.com/rails/globalid). # - # This compatibility patch implements Global ID for decorated objects by delegating to the object - # that is decorated. This means you can pass decorated objects to background jobs, but - # the object won't be decorated when it is deserialized. This patch is meant as an intermediate - # fix until we can find a way to deserialize the decorated object correctly. + # This compatibility patch implements Global ID for decorated objects by defining `.find(id)` + # class method that uses the original one and decorates the result. + # This means you can pass decorated objects to background jobs and they will be decorated when + # deserialized. module GlobalID extend ActiveSupport::Concern included do include ::GlobalID::Identification + end - delegate :to_global_id, :to_signed_global_id, to: :object + class_methods do + def find(*args) + object_class.find(*args).decorate + end end end end diff --git a/spec/dummy/spec/decorators/post_decorator_spec.rb b/spec/dummy/spec/decorators/post_decorator_spec.rb index e1655b9a..7260e68b 100644 --- a/spec/dummy/spec/decorators/post_decorator_spec.rb +++ b/spec/dummy/spec/decorators/post_decorator_spec.rb @@ -61,4 +61,13 @@ it "uses a test view context from BaseController" do expect(Draper::ViewContext.current.controller).to be_an BaseController end + + describe 'Global ID' do + it { expect(GlobalID::Locator.locate decorator.to_gid).to eq decorator } + it { expect(GlobalID::Locator.locate decorator.to_gid).to be_decorated } + it { expect(GlobalID::Locator.locate object.to_gid).not_to be_decorated } + it { expect(GlobalID::Locator.locate_signed decorator.to_sgid).to eq decorator } + it { expect(GlobalID::Locator.locate_signed decorator.to_sgid).to be_decorated } + it { expect(GlobalID::Locator.locate_signed object.to_sgid).not_to be_decorated } + end end diff --git a/spec/dummy/spec/jobs/publish_post_job_spec.rb b/spec/dummy/spec/jobs/publish_post_job_spec.rb index e0ffbb15..c809f42a 100644 --- a/spec/dummy/spec/jobs/publish_post_job_spec.rb +++ b/spec/dummy/spec/jobs/publish_post_job_spec.rb @@ -4,6 +4,8 @@ subject(:job) { described_class.perform_later(post) } it 'queues the job' do - expect { job }.to have_enqueued_job(described_class).with(post.object) + expect { job }.to have_enqueued_job(described_class).with { |post| + expect(post).to be_decorated + } end end diff --git a/spec/dummy/spec/models/post_spec.rb b/spec/dummy/spec/models/post_spec.rb index 22a5fb61..1ddf8b56 100644 --- a/spec/dummy/spec/models/post_spec.rb +++ b/spec/dummy/spec/models/post_spec.rb @@ -5,11 +5,4 @@ it_behaves_like 'a decoratable model' it { should be_a ApplicationRecord } - - describe '#to_global_id' do - let(:post) { Post.create } - subject { post.to_global_id } - - it { is_expected.to eq post.decorate.to_global_id } - end end