复制activerecord记录的最简单方法是什么?

Bre*_*nt 402 ruby ruby-on-rails rails-activerecord

我想制作一个activerecord记录的副本,更改进程中的单个字段(除了id).实现这一目标的最简单方法是什么?

我意识到我可以创建一个新记录,然后遍历每个字段逐个复制数据 - 但我认为必须有一个更简单的方法来做到这一点......

如:

 @newrecord=Record.copy(:id)  *perhaps?*
Run Code Online (Sandbox Code Playgroud)

Mic*_*cot 610

要获取副本,请使用克隆(或dup for rails 3.1)方法:

# rails < 3.1
new_record = old_record.clone

#rails >= 3.1
new_record = old_record.dup
Run Code Online (Sandbox Code Playgroud)

然后你可以改变你想要的任何字段.

ActiveRecord会覆盖内置的Object#clone,为您提供一个带有未分配ID的新记录(未保存到数据库).
请注意,它不会复制关联,因此如果需要,您必须手动执行此操作.

Rails 3.1 clone是一个浅拷贝,使用dup代替...

  • 绝对不要使用克隆.正如其他海报所提到的,克隆方法现在委托使用Kernel#clone来复制id.从现在开始使用ActiveRecord :: Base#dup (73认同)
  • 看起来这个功能已被替换为dup:https://gist.github.com/994614 (12认同)
  • 这仍然适用于Rails 3.1.0.beta吗?当我做`q = p.clone`,然后是'p == q`时,我得到了`true`.另一方面,如果我使用`q = p.dup`,比较它时会得到'false`. (6认同)
  • 我不得不说,这是一个真正的痛苦.如果您没有良好的规范覆盖范围,那么像这样的简单更改可能会削弱一些重要的功能. (5认同)
  • 如果你想改变特定的属性,对 `dup` 或 `clone` 的补充是使用 `tap` 例如 `clone = record.dup.tap { |new_clone| new_clone.name = "dup_#{new_clone.name}" }` (3认同)

Phi*_*bbe 73

根据您的需要和编程风格,您还可以结合使用类的新方法和合并.由于缺少一个更好的简单示例,假设您有一个任务安排在某个特定日期,并且您希望将其复制到另一个日期.任务的实际属性并不重要,因此:

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

将使用:id => nil,:scheduled_on => some_new_date和所有其他属性创建一个与原始任务相同的新任务.使用Task.new,您必须显式调用save,因此如果您希望自动保存它,请将Task.new更改为Task.create.

和平.

  • 你不明白这是多么好的想法.警告:无法批量分配受保护的属性:id,due_date,created_at,updated_at`返回 (5认同)
  • @RubenMartineJr.我知道这是一个旧帖子,但是你可以通过在属性hash上使用'.except'来解决这个问题:new_task = Task.new(old_task.attributes.except(:attribute_you_dont_want,:another_aydw).merge({:scheduled_on => some_new_date})) (2认同)
  • 不幸的是, old_task.attributes 也分配了 ID 字段。这对我不起作用 (2认同)

Vau*_*hon 32

您可能也喜欢ActiveRecord 3.2 的Amoeba宝石.

在你的情况,你可能想使用的nullify,regexprefix在配置DSL可用的选项.

它支持的简单和自动递归重复has_one,has_manyhas_and_belongs_to_many协会,现场预处理和既能对模型和动态应用了灵活而强大的配置DSL.

请务必查看Amoeba文档,但使用非常简单......

只是

gem install amoeba
Run Code Online (Sandbox Code Playgroud)

或添加

gem 'amoeba'
Run Code Online (Sandbox Code Playgroud)

到你的Gemfile

然后将变形虫块添加到模型中并dup像往常一样运行方法

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    enable
  end
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

class Tag < ActiveRecord::Base
  has_and_belongs_to_many :posts
end

class PostsController < ActionController
  def some_method
    my_post = Post.find(params[:id])
    new_post = my_post.dup
    new_post.save
  end
end
Run Code Online (Sandbox Code Playgroud)

您还可以控制以多种方式复制哪些字段,但是,例如,如果您希望防止注释被复制但是您想要维护相同的标记,则可以执行以下操作:

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    exclude_field :comments
  end
end
Run Code Online (Sandbox Code Playgroud)

您还可以预处理字段,以帮助指示前缀和后缀以及正则表达式的唯一性.此外,还有许多选项,因此您可以为您的目的以最易读的方式编写:

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"}
  end
end
Run Code Online (Sandbox Code Playgroud)

关联的递归复制很容易,也可以在子模型上启用变形虫

class Post < ActiveRecord::Base
  has_many :comments

  amoeba do
    enable
  end
end

class Comment < ActiveRecord::Base
  belongs_to :post
  has_many :ratings

  amoeba do
    enable
  end
end

class Rating < ActiveRecord::Base
  belongs_to :comment
end
Run Code Online (Sandbox Code Playgroud)

配置DSL有更多选项,因此请务必查看文档.

请享用!:)

  • 只是在这里修复一下。正确的方法是“.amoeba_dup”,而不仅仅是“.dup”。我试图执行这段代码,但它在这里不起作用。 (2认同)

bra*_*ing 30

如果您不想复制id,请使用ActiveRecord :: Base#dup


Fra*_*eil 23

我通常只是复制属性,改变我需要改变的东西:

new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
Run Code Online (Sandbox Code Playgroud)

  • 要使用Rails 4创建新记录,请执行`User.create(old_user.attributes.merge({login:"newlogin",id:nil}))`.这将保存具有正确唯一ID的新用户. (4认同)

rai*_*ive 10

如果您需要带关联的深层副本,我建议使用deep_cloneable gem.


小智 6

在 Rails 5 中,您可以像这样简单地创建重复的对象或记录。

new_user = old_user.dup
Run Code Online (Sandbox Code Playgroud)