Rails克隆、复制或重复问题

11

我有一个嵌套表单,保存后,我想在show页面上点击一个链接来复制或克隆该表单,并打开一个新表单。然后我应该能够进行编辑(如一个新的ID)并将其保存为一个新记录。我看过一些类似于deep_cloneable gem的示例,但我不知道如何实现它。我认为这应该很简单,但我不理解在控制器和展示页面中放置东西的位置。

4个回答

22

如果你想复制一个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

谢谢,那么在我的控制器中添加后,视图中的link_to标签应该如何呈现? - FattRyan
你是Rails新手吗? 在展示页面上,您需要呈现一些链接,例如link_to "复制到新记录",{:controller=>"您的控制器",:action=>'create_from_existing',:id=>params[:id]} 此外,在route.rb文件中定义create_from_existing操作的路由。如果您想在现有页面上显示此表单,则可以使用ajax,使用link_to_remote(link_to :remote=>true, rails 3) - Naren Sisodiya
2
这个处理 has_many 的方式是怎样的?它会为子对象创建新记录还是使用相同的记录? - Mike
5
如果@existing_post具有任何不可批量赋值的属性,那么这将会失败。您必须拒绝受保护或唯一的属性,例如 id - JellicleCat
1
这里有一个答案,其中克隆涉及保留关联记录。 (https://dev59.com/m2025IYBdhLWcg3wfmDw) - tirdadc

21

我发现这些答案有点难以理解。一个答案展示了这个:

@post = Post.new(@existing_post.attributes)

由于该方法仍会传递id和时间戳值,因此它将无法正常工作。我使用.dup进行修复,并在我的答案中展示了这一点。

以下是我如何从现有项目创建新项目。

该模型适用于产品(Product),控制器为Products_Controller.rb。我们将向控制器添加一个名为“copy”的新操作,并在现有产品的“show”视图中链接到它,并渲染一个填好内容的“new”视图,可随时进行编辑和保存。

首先在routes.rb中创建一个路由,用于“copy”操作。

# 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) %>

3
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

2

值得一提的是模型上的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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接