What is the easiest way to duplicate an activerecord record? What is the easiest way to duplicate an activerecord record? ruby ruby

What is the easiest way to duplicate an activerecord record?


To get a copy, use the clone (or dup for rails 3.1+) method:

# rails < 3.1new_record = old_record.clone#rails >= 3.1new_record = old_record.dup

Then you can change whichever fields you want.

ActiveRecord overrides the built-in Object#clone to give you a new (not saved to the DB) record with an unassigned ID.
Note that it does not copy associations, so you'll have to do this manually if you need to.

Rails 3.1 clone is a shallow copy, use dup instead...


Depending on your needs and programming style, you can also use a combination of the new method of the class and merge. For lack of a better simple example, suppose you have a task scheduled for a certain date and you want to duplicate it to another date. The actual attributes of the task aren't important, so:

old_task = Task.find(task_id)new_task = Task.new(old_task.attributes.merge({:scheduled_on => some_new_date}))

will create a new task with :id => nil, :scheduled_on => some_new_date, and all other attributes the same as the original task. Using Task.new, you will have to explicitly call save, so if you want it saved automatically, change Task.new to Task.create.

Peace.


You may also like the Amoeba gem for ActiveRecord 3.2.

In your case, you probably want to make use of the nullify, regex or prefix options available in the configuration DSL.

It supports easy and automatic recursive duplication of has_one, has_many and has_and_belongs_to_many associations, field preprocessing and a highly flexible and powerful configuration DSL that can be applied both to the model and on the fly.

be sure to check out the Amoeba Documentation but usage is pretty easy...

just

gem install amoeba

or add

gem 'amoeba'

to your Gemfile

then add the amoeba block to your model and run the dup method as usual

class Post < ActiveRecord::Base  has_many :comments  has_and_belongs_to_many :tags  amoeba do    enable  endendclass Comment < ActiveRecord::Base  belongs_to :postendclass Tag < ActiveRecord::Base  has_and_belongs_to_many :postsendclass PostsController < ActionController  def some_method    my_post = Post.find(params[:id])    new_post = my_post.dup    new_post.save  endend

You can also control which fields get copied in numerous ways, but for example, if you wanted to prevent comments from being duplicated but you wanted to maintain the same tags, you could do something like this:

class Post < ActiveRecord::Base  has_many :comments  has_and_belongs_to_many :tags  amoeba do    exclude_field :comments  endend

You can also preprocess fields to help indicate uniqueness with both prefixes and suffixes as well as regexes. In addition, there are also numerous options so you can write in the most readable style for your purpose:

class Post < ActiveRecord::Base  has_many :comments  has_and_belongs_to_many :tags  amoeba do    include_field :tags    prepend :title => "Copy of "    append :contents => " (copied version)"    regex :contents => {:replace => /dog/, :with => "cat"}  endend

Recursive copying of associations is easy, just enable amoeba on child models as well

class Post < ActiveRecord::Base  has_many :comments  amoeba do    enable  endendclass Comment < ActiveRecord::Base  belongs_to :post  has_many :ratings  amoeba do    enable  endendclass Rating < ActiveRecord::Base  belongs_to :commentend

The configuration DSL has yet more options, so be sure to check out the documentation.

Enjoy! :)