考虑这个简单:has_many relationship:
class Basket < ActiveRecord::Base
has_many :apples
...
end
class Apple < ActiveRecord::Base
belongs_to :basket
end
现在,我在Basket类中有一个方法,其中我想创建'apples'数组的临时副本并操作临时副本。对于初学者,我想在临时副本中添加一个新元素,如下所示:
class Basket < ActiveRecord::Base
has_many :apples
def do_something
#create a temporary working copy of the apples array
temp_array = self.apples
#create a new Apple object to insert in the temporary array
temp_apple = Apple.new
#add to my temporary array only
temp_array << temp_apple
#Problem! temp_apple.validate gets called but I don't want it to.
end
end
当我这样做时,我发现当我尝试将其添加到临时数组时,会在临时Apple对象上调用validate例程。我创建临时数组的全部原因是为了避免主数组附带的所有行为,例如验证,数据库插入等......
那就是说,我确实找到了一种蛮力的方法来避免这个问题,在for循环中一次创建一个temp_array对象,如下所示。这有效,但很难看。我想知道是否有一种更优雅的方式来实现这一目标。
class Basket < ActiveRecord::Base
has_many :apples
def do_something
#create a temporary working copy of the apples array
temp_array = []
for x in self.apples
temp_array << x
end
#create a new Apple object to insert in the temporary array
temp_apple = Apple.new
#add to my temporary array only
temp_array << temp_apple
#Yippee! the temp_apple.validate routine doesn't get called this time!.
end
end
如果有人比我听到的更能解决这个问题,我很乐意听到。
谢谢!
答案 0 :(得分:9)
问题是self.apples
实际上不是一个数组 - 它是一个Relation,一旦你对它应用了一个Array / Enumerable方法就会解决它。所以,在此之后:temp_array = self.apples
甚至没有触发SQL查询。
强制获取数据并摆脱所有关系行为的简单解决方案就是使用方法all
:
#create a temporary working copy of the apples array
temp_array = self.apples.all
答案 1 :(得分:2)
temp_array = self.apples # => This results in an instance of ActiveRecord::Relation, not an Array
您可以尝试明确评估关系
temp_array = self.apples.all # => This will give you an Array
答案 2 :(得分:1)
我觉得使用self.apples.to_a
(= to_array)更合乎逻辑:
基本上,ActiveRecord::Relation
是一个扩展Array
本身的对象,这意味着它具有所有Array
技能但更多。
如果您需要降低ActiveRecord::Relation
的技能,请将其转换为数组并保持良好状态。