用rails在一个调用中保存多个对象

我有一个方法在轨道上做这样的事情:

a = Foo.new("bar") a.save b = Foo.new("baz") b.save ... x = Foo.new("123", :parent_id => a.id) x.save ... z = Foo.new("zxy", :parent_id => b.id) z.save 

问题是这需要越来越多的实体,我添加。 我怀疑这是因为它必须击中每个logging的数据库。 既然他们是嵌套的,我知道在父母得救之前我不能拯救孩子,但是我想立刻拯救所有的父母,然后是所有的孩子。 这将是很好的做一些事情,如:

 a = Foo.new("bar") b = Foo.new("baz") ... saveall(a,b,...) x = Foo.new("123", :parent_id => a.id) ... z = Foo.new("zxy", :parent_id => b.id) saveall(x,...,z) 

这将只有两个数据库命中。 有没有一种简单的方法来做到这一点在轨道上,还是我坚持做一个一次?

您可以尝试使用Foo.create而不是Foo.new。 创build“创build一个对象(或多个对象)并将其保存到数据库,如果validation通过,将返回结果对象,无论对象是否成功保存到数据库。

你可以像这样创build多个对象:

 # Create an Array of new objects parents = Foo.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) 

然后,对于每个家长,您也可以使用create添加到其关联中:

 parents.each do |parent| parent.children.create (:child_name => 'abc') end 

我build议阅读ActiveRecord文档和ActiveRecord查询接口和ActiveRecord关联的Rails指南。 后者包含一个class级在宣布关联时获得的所有方法的指南。

由于您需要执行多个插入,数据库将被多次命中。 你的情况的延迟是因为每个保存都是在不同的数据库事务中完成的。 您可以通过将所有操作放在一个事务中来减less延迟。

 class Foo belongs_to :parent, :class_name => "Foo" has_many :children, :class_name => "Foo", :foreign_key=> "parent_id" end 

您的保存方法可能如下所示:

 # build the parent and the children a = Foo.new(:name => "bar") a.children.build(:name => "123") b = Foo.new("baz") b.children.build(:name => "zxy") #save parents and their children in one transaction Foo.transaction do a.save b.save end 

父对象上的save调用将保存子对象。

在其他地方find了两个答案之一:由Beerlington 。 这两个是你最好的performance


我认为最好的方法是使用SQL,每个查询批量插入多行。 如果你可以构build一个INSERT语句来执行如下操作:

INSERT INTO foos_bars(foo_id,bar_id)VALUES(1,1),(1,2),(1,3)….您应该可以在单个查询中插入数千行。 我没有尝试你的mass_habtm方法,但似乎你可以像这样的东西:

 bars = Bar.find_all_by_some_attribute(:a) foo = Foo.create values = bars.map {|bar| "(#{foo.id},#{bar.id})"}.join(",") connection.execute("INSERT INTO foos_bars (foo_id, bar_id) VALUES #{values}") 

此外,如果您通过“some_attribute”searchBar,请确保您的数据库中已有该字段的索引。


要么

你仍然可以看看activerecord-import。 没有模型是没有用的,但是你可以为导入创build一个模型。

 FooBar.import [:foo_id, :bar_id], [[1,2], [1,3]] 

干杯

你不需要一个gem快速打DB,只需要一次!

Jackrg为我们解决了这个问题: https ://gist.github.com/jackrg/76ade1724bd816292e4e