-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from elardo/add-after-clone-callback
Add after_clone callback
- Loading branch information
Showing
14 changed files
with
235 additions
and
8 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
id: after_clone | ||
title: After Clone | ||
--- | ||
|
||
The `after_clone` callbacks can help you to make additional operations on cloned record, like checking it with some business logic or actualizing cloned record attributes, before it will be saved to the database. Also it can help to avoid unneeded usage of [`after_persist`](after_persist.md) callbacks, and additional queries to database. | ||
|
||
Examples: | ||
|
||
```ruby | ||
class User < ActiveRecord::Base | ||
# create_table :users do |t| | ||
# t.string :login | ||
# t.integer :draft_count | ||
# end | ||
|
||
has_many :posts # all user's posts | ||
end | ||
|
||
class Post < ActiveRecord::Base | ||
# create_table :posts do |t| | ||
# t.integer :user_id | ||
# t.boolean :is_draft | ||
# end | ||
|
||
scope :draft, -> { where is_draft: true } | ||
end | ||
|
||
class UserCloner < Clowne::Cloner | ||
# clone user and his posts, which is drafts | ||
include_association :posts, scope: :draft | ||
|
||
after_clone do |_origin, clone, **| | ||
# actualize user attribute | ||
clone.draft_count = clone.posts.count | ||
end | ||
end | ||
``` | ||
|
||
`after_clone` runs when you call `Operation#to_record` or [`Operation#persist`]('operation.md) (or `Operation#persist!`) | ||
|
||
```ruby | ||
# prepare data | ||
user = User.create | ||
3.times { Post.create(user: user, is_draft: false) } | ||
2.times { Post.create(user: user, is_draft: true) } | ||
|
||
operation = UserCloner.call(user) | ||
# => <#Clowne::Utils::Operation ...> | ||
|
||
clone = operation.to_record | ||
# => <#User id: nil, draft_count: 2 ...> | ||
|
||
clone.draft_count == user.posts.draft.count | ||
# => true | ||
``` |
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
"exclude_association", | ||
"nullify", | ||
"finalize", | ||
"after_clone", | ||
"after_persist", | ||
"init_as", | ||
"traits", | ||
|
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# frozen_string_literal: true | ||
|
||
module Clowne | ||
module Declarations | ||
class AfterClone < Base # :nodoc: all | ||
attr_reader :block | ||
|
||
def initialize | ||
raise ArgumentError, 'Block is required for after_clone' unless block_given? | ||
|
||
@block = Proc.new | ||
end | ||
|
||
def compile(plan) | ||
plan.add(:after_clone, self) | ||
end | ||
end | ||
end | ||
end | ||
|
||
Clowne::Declarations.add :after_clone, Clowne::Declarations::AfterClone |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# frozen_string_literal: true | ||
|
||
module Clowne | ||
class Resolvers | ||
module AfterClone # :nodoc: all | ||
def self.call(source, record, declaration, params:, **_options) | ||
operation = Clowne::Utils::Operation.current | ||
operation.add_after_clone( | ||
proc do | ||
declaration.block.call(source, record, params) | ||
end | ||
) | ||
record | ||
end | ||
end | ||
end | ||
end |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
describe 'Pre processing', :cleanup, adapter: :active_record, transactional: :active_record do | ||
before(:all) do | ||
module AR | ||
class TopicCloner < Clowne::Cloner | ||
include_association :posts | ||
|
||
after_clone do |_origin, clone, **| | ||
raise Clowne::UnprocessableSourceError, 'Topic has no posts!' if clone.posts.empty? | ||
end | ||
end | ||
end | ||
end | ||
|
||
after(:all) do | ||
AR.send(:remove_const, 'TopicCloner') | ||
end | ||
|
||
let!(:topic) { create(:topic) } | ||
|
||
describe 'The main idea of "after clone" feature is a possibility | ||
to make some additional work or checks on cloned record before | ||
persisting it.' do | ||
|
||
subject(:operation) { AR::TopicCloner.call(topic) } | ||
|
||
it 'raises error' do | ||
expect do | ||
operation.persist | ||
end.to raise_error(Clowne::UnprocessableSourceError) | ||
end | ||
end | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
describe 'Sequel Post Processing', :cleanup, adapter: :sequel, transactional: :sequel do | ||
before(:all) do | ||
module Sequel | ||
class TopicCloner < Clowne::Cloner | ||
include_association :posts | ||
|
||
after_clone do |_origin, clone, **| | ||
raise Clowne::UnprocessableSourceError, 'Topic has no posts!' if clone.posts.empty? | ||
end | ||
end | ||
end | ||
end | ||
|
||
after(:all) do | ||
Sequel.send(:remove_const, 'TopicCloner') | ||
end | ||
|
||
let!(:topic) { create('sequel:topic') } | ||
|
||
describe 'The main idea of "after clone" feature is a possibility | ||
to make some additional work or checks on cloned record before | ||
persisting it.' do | ||
|
||
subject(:operation) { Sequel::TopicCloner.call(topic) } | ||
|
||
it 'raises error' do | ||
expect do | ||
operation.to_record | ||
end.to raise_error(Clowne::UnprocessableSourceError) | ||
end | ||
end | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
describe Clowne::Resolvers::AfterClone do | ||
let(:declaration) { Clowne::Declarations::AfterClone.new(&block) } | ||
|
||
describe '.call' do | ||
let(:source) { AR::User.create(email: '[email protected]') } | ||
let(:params) { {} } | ||
let(:block) do | ||
proc do |_source, record| | ||
record.email = '[email protected]' | ||
end | ||
end | ||
|
||
subject(:result) do | ||
record = AR::User.new | ||
operation = Clowne::Utils::Operation.wrap do | ||
described_class.call(source, record, declaration, params: params) | ||
end | ||
operation.persist | ||
operation.to_record | ||
end | ||
|
||
it 'execute after_clone block' do | ||
expect(result).to be_a(AR::User) | ||
expect(result.email).to eq('[email protected]') | ||
end | ||
|
||
context 'with params' do | ||
let(:params) { { email: '[email protected]' } } | ||
let(:block) do | ||
proc do |_source, record, params| | ||
record.email = params[:email] | ||
end | ||
end | ||
|
||
it 'execute after_clone block with params' do | ||
expect(result).to be_a(AR::User) | ||
expect(result.email).to eq('[email protected]') | ||
end | ||
end | ||
end | ||
end |