Rails clone copy or duplicate
If you want to copy an activeRecord object you can use its attributes to create new one like
you can have an action in your controller which can be called on link,
def create_from_existing
@existing_post = Post.find(params[:id])
#create new object with attributes of existing record
@post = Post.new(@existing_post.attributes)
render "your_post_form"
end
Also worth mentioning is the dup
method on a model. It makes a copy with all attributes and outgoing relations but sets id
to nil
. Like this (borrowing code from Naren Sisodiya):
def create_from_existing
@existing_post = Post.find(params[:id])
#create new object with attributes of existing record
@post = @existing_post.dup
render "your_post_form"
end
I found these answers a little hard to follow. One answer shows this:
@post = Post.new(@existing_post.attributes)
which will not work as it will also pass the id, and timestamp values. I used .dup to fix that and I show that in my answer.
Here's how I achieved creating a new item from an existing item.
The model is for a Product, the controller Products_Controller.rb. We're going to add a new action to the controller called copy
and we're going to link to it from the show
view on an existing Product and render a filled out new
view ready to be edited and saved.
First we create a route for the copy action in routes.rb
# Routes.rb
resources :Products do
member do
get 'copy'
end
end
Then a copy action in Products_controller.rb
# ProductController.rb
def copy
@source = Product.find(params[:id])
@product = @source.dup
render 'new'
end
Now we need to add a Link to the show
view to call our copy action.
# show.html.erb
<%= link_to "copy", copy_product_path(params[:id]) %>
Rails 4-6 Update:
The strong parameter scaffold makes it even shorter:
# ProductController.rb
# GET /products/1/copy
def copy
@product = @product.dup
render :new
end
And in the erb template:
# show.html.erb
<%= link_to "copy", copy_product_path(@product) %>
class Foo < ActiveRecord::Base
def self.clone_from(parent)
parent = find(parent) unless parent.kind_of? Foo
foo = self.new
foo.attributes = parent.attributes
# if you want to also clone a habtm:
foo.some_association_ids = parent.some_association_ids
# etc.
foo
end
end
class FoosController < ApplicationController
def clone
foo = Foo.clone_from(params[:id])
respond_with(foo)
end
end