【问题标题】:Ruby on Rails deep copy/ deep clone of object and its attributesRuby on Rails 深拷贝/深克隆对象及其属性
【发布时间】:2011-09-16 17:18:39
【问题描述】:

我想对包含所有属性的对象进行深度复制。

experiment_old 有 10 次试验。我想通过 10 次试验将所有内容复制到experiment_new。 Experiment_old 还应保留 10 次试用信息。

但是,我在下面尝试的所有案例,它们都很好地复制了所有内容,但是experiment_old 没有 10 次试验信息。他们只是出现在 Experiment_new 上。

对这些情况进行深度复制的最佳方法是什么。

案例一:

@experiment_new = Experiment.create(@experiment_old.attributes.merge(:trials => experiment_old.trails))

案例2:

@experiment_new = Marshal.load(Marshal.dump(@experiment_old.trials))

案例3:

@experiment_new = @experiment_old.clone

这是模型:

class Experiment < ActiveRecord::Base
  belongs_to :experimenter
  has_many :trials
  has_many :participants
end


class Trial < ActiveRecord::Base
  belongs_to :experiment
  belongs_to :datum
  belongs_to :condition
  has_one :result_trial
end

【问题讨论】:

  • 试验属于_试验,对吧?您可以发布对象的模型吗?
  • 每当我遇到作为对象模型核心的深度克隆时,我建议使用 NoSQL DB,例如 MongoDB w/Mongoid

标签: ruby-on-rails deep-copy


【解决方案1】:

您可以享受 ActiveRecord 3.2 的Amoeba gem

它支持has_onehas_manyhas_and_belongs_to_many 关联的简单自动递归复制、字段预处理和高度灵活且功能强大的配置 DSL,可同时应用于模型和动态。

请务必查看Amoeba Documentation,但使用起来非常简单...

只是

gem install amoeba

或添加

gem 'amoeba'

到你的 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

您的新帖子应该包含最初与之关联的所有标签,并且所有 cmets 也应该被复制。您可以通过 DSL 禁用各种记录的重复,您可以在文档中阅读相关内容,但例如,如果您想保留标签,而不是 cmets,您可以执行以下操作:

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

  amoeba do
    include_field :comments
  end
end

或使用独占语法

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

  amoeba do
    exclude_field :comments
  end
end

或通过指定要识别(并因此复制)的字段类型

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

  amoeba do
    recognize :has_and_belongs_to_many
  end
end

这些不同的选项中的每一个都应该导致新帖子与旧帖子的标签相同,但不会复制 cmets。

如果您启用它们,Amoeba 也会自动递归到子记录中

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

你也可以在字段前加上一些额外的数据来表示唯一性

class Post < ActiveRecord::Base
  has_many :comments

  amoeba do
    enable
    prepend :title => "Copy of "
  end
end

除了前置之外,您还可以在给定字段上附加或运行正则表达式

享受吧! :)

【讨论】:

  • 非常好的帖子!这甚至可能是 gem 的自述文件! =p
  • 在你的例子中不应该是include_field :tags吗?当您不想复制它们时,包括 cmets 对我来说没有意义。
  • 旧帖,但偶然发现。与其多次发布完全相同的答案,不如将其标记为欺骗并引用被欺骗的问题。 stackoverflow.com/a/9485672/438992
【解决方案2】:

您应该克隆每个试验并将它们分配给克隆的试验:

@experiment_new = @experiment_old.clone
@experiment_old.trials.each do |trial|
  @experiment_new.trials << trial.clone
end

【讨论】:

    猜你喜欢
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    • 2010-11-30
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多