【发布时间】:2011-08-08 08:39:42
【问题描述】:
我有一个嵌套表单,保存后,我希望能够单击显示页面上的链接来复制或克隆该表单并打开一个新表单。从那里我应该能够进行编辑(如新 id)并保存为新记录。我见过一些像deep_cloneable gem 这样的例子,但我不知道如何实现它。我认为这应该很简单,但我只是不明白在控制器和显示视图中放置东西的位置。
【问题讨论】:
标签: ruby-on-rails-3 duplicates copy clone
我有一个嵌套表单,保存后,我希望能够单击显示页面上的链接来复制或克隆该表单并打开一个新表单。从那里我应该能够进行编辑(如新 id)并保存为新记录。我见过一些像deep_cloneable gem 这样的例子,但我不知道如何实现它。我认为这应该很简单,但我只是不明白在控制器和显示视图中放置东西的位置。
【问题讨论】:
标签: ruby-on-rails-3 duplicates copy clone
如果你想复制一个 activeRecord 对象,你可以使用它的属性来创建一个新的像
你可以在你的控制器中有一个可以在链接上调用的动作,
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
【讨论】:
@existing_post 有任何不可批量分配的属性,这将失败。您必须拒绝受保护或独特的属性,例如 id。
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
【讨论】:
我发现这些答案有点难以理解。一个答案表明:
@post = Post.new(@existing_post.attributes)
这不起作用,因为它还会传递 id 和时间戳值。我使用 .dup 解决了这个问题,并在我的回答中展示了这一点。
以下是我如何从现有项目创建新项目。
该模型用于产品,即控制器 Products_Controller.rb。我们将向控制器添加一个名为copy 的新操作,我们将从现有产品上的show 视图链接到它,并呈现一个填充好的new 视图以供编辑和保存.
首先我们在routes.rb中为复制操作创建一个路由
# Routes.rb
resources :Products do
member do
get 'copy'
end
end
然后是 Products_controller.rb 中的一个复制动作
# ProductController.rb
def copy
@source = Product.find(params[:id])
@product = @source.dup
render 'new'
end
现在我们需要向show 视图添加一个链接来调用我们的复制操作。
# show.html.erb
<%= link_to "copy", copy_product_path(params[:id]) %>
Rails 4-6 更新:
强大的参数脚手架使其更短:
# ProductController.rb
# GET /products/1/copy
def copy
@product = @product.dup
render :new
end
在erb模板中:
# show.html.erb
<%= link_to "copy", copy_product_path(@product) %>
【讨论】:
另外值得一提的是模型上的dup 方法。它会创建一个包含所有属性和传出关系的副本,但将id 设置为nil。像这样(借用 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
【讨论】: