[Awesome Ruby Gem] Use amoeba gem to clone active_record objects including associations and several operations

amoeba

Easy cloning of active_record objects including associations and several operations under associations and attributes.

The goal was to be able to easily and quickly reproduce ActiveRecord objects including their children, for example copying a blog post maintaining its associated tags or categories.

Features

  • Supports the following association types

    • has_many

    • has_one :through

    • has_many :through

    • has_and_belongs_to_many

  • A simple DSL for configuration of which fields to copy. The DSL can be applied to your rails models or used on the fly.

  • Supports STI (Single Table Inheritance) children inheriting their parent amoeba settings.

  • Multiple configuration styles such as inclusive, exclusive and indiscriminate (aka copy everything).

  • Supports cloning of the children of Many-to-Many records or merely maintaining original associations

  • Supports automatic drill-down i.e. recursive copying of child and grandchild records.

  • Supports preprocessing of fields to help indicate uniqueness and ensure the integrity of your data depending on your business logic needs, e.g. prepending "Copy of " or similar text.

  • Supports preprocessing of fields with custom lambda blocks so you can do basically whatever you want if, for example, you need some custom logic while making copies.

  • Amoeba can perform the following preprocessing operations on fields of copied records

    • set

    • prepend

    • append

    • nullify

    • customize

    • regex

Installation

You can install it as a gem:

1
$ gem install amoeba

or add it into a Gemfile (Bundler):

1
2
3
4
5
# Gemfile

# GitHub - amoeba-rb/amoeba: A ruby gem to allow the copying of ActiveRecord objects and their associated children, configurable with a DSL on the model
# https://github.com/amoeba-rb/amoeba
gem 'amoeba', '3.2.0'

Then, run bundle install.

1
$ bundle install

Usages

Configure your models with one of the styles below and then just run the amoeba_dup method on your model where you would run the dup method normally:

Indiscriminate Style

This is the most basic usage case and will simply enable the copying of any known associations.

If you have some models for a blog about like this:

1
2
3
4
5
6
7
class Post < ActiveRecord::Base
has_many :comments
end

class Comment < ActiveRecord::Base
belongs_to :post
end

simply add the amoeba configuration block to your model and call the enable method to enable the copying of child records, like this:

1
2
3
4
5
6
7
8
9
10
11
class Post < ActiveRecord::Base
has_many :comments

amoeba do
enable
end
end

class Comment < ActiveRecord::Base
belongs_to :post
end

Child records will be automatically copied when you run the amoeba_dup method.

Inclusive Style

If you only want some of the associations copied but not others, you may use the inclusive style:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Post < ActiveRecord::Base
has_many :comments
has_many :tags
has_many :authors

amoeba do
enable
include_association :tags
include_association :authors
end
end

class Comment < ActiveRecord::Base
belongs_to :post
end

Using the inclusive style within the amoeba block actually implies that you wish to enable amoeba, so there is no need to run the enable method, though it won’t hurt either:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Post < ActiveRecord::Base
has_many :comments
has_many :tags
has_many :authors

amoeba do
include_association :tags
include_association :authors
end
end

class Comment < ActiveRecord::Base
belongs_to :post
end

You may also specify fields to be copied by passing an array. If you call the include_association with a single value, it will be appended to the list of already included fields. If you pass an array, your array will overwrite the original values.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Post < ActiveRecord::Base
has_many :comments
has_many :tags
has_many :authors

amoeba do
include_association [:tags, :authors]
end
end

class Comment < ActiveRecord::Base
belongs_to :post
end

These examples will copy the post’s tags and authors but not its comments.

The inclusive style, when used, will automatically disable any other style that was previously selected.

Exclusive Style

If you have more fields to include than to exclude, you may wish to shorten the amount of typing and reading you need to do by using the exclusive style. All fields that are not explicitly excluded will be copied:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Post < ActiveRecord::Base
has_many :comments
has_many :tags
has_many :authors

amoeba do
exclude_association :comments
end
end

class Comment < ActiveRecord::Base
belongs_to :post
end

This example does the same thing as the inclusive style example, it will copy the post’s tags and authors but not its comments. As with inclusive style, there is no need to explicitly enable amoeba when specifying fields to exclude.

The exclusive style, when used, will automatically disable any other style that was previously selected, so if you selected include fields, and then you choose some exclude fields, the exclude_association method will disable the previously selected inclusive style and wipe out any corresponding include fields.

Conditions

Also if you need to path extra condition for include or exclude relationship you can path method name to :if option.

1
2
3
4
5
6
7
8
9
10
11
12
class Post < ActiveRecord::Base
has_many :comments
has_many :tags

amoeba do
include_association :comments, if: :popular?
end

def popular?
likes > 15
end
end

After call Post.first.amoeba_dup if likes is larger 15 than all comments will be duplicated too, but in another situation - no relations will be cloned. Same behavior will be for exclude_association.

Be aware! If you wrote:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Post < ActiveRecord::Base
has_many :comments
has_many :tags

amoeba do
exclude_association :tags
include_association :comments, if: :popular?
end

def popular?
likes > 15
end
end

inclusion strategy will be chosen regardless of the result of popular? method call (the same for reverse situation).

See GitHub - amoeba-rb/amoeba: A ruby gem to allow the copying of ActiveRecord objects and their associated children, configurable with a DSL on the model - https://github.com/amoeba-rb/amoeba to learn more Usages.

References

[1] GitHub - amoeba-rb/amoeba: A ruby gem to allow the copying of ActiveRecord objects and their associated children, configurable with a DSL on the model - https://github.com/amoeba-rb/amoeba

[2] amoeba | RubyGems.org | your community gem host - https://rubygems.org/gems/amoeba/

[3] GitHub - clowne-rb/clowne: A flexible gem for cloning models - https://github.com/clowne-rb/clowne

[4] Clowne: Clone Ruby models with a smile — Martian Chronicles, Evil Martians’ team blog - https://evilmartians.com/chronicles/clowne-clone-ruby-models-with-a-smile

[5] GitHub - moiristo/deep_cloneable: This gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations. - https://github.com/moiristo/deep_cloneable

[6] Duplicating models with complex nested associations - CookiesHQ - https://www.cookieshq.co.uk/posts/duplicating-models-with-complex-nested-associations