ActiveRecord:将has_many列表视为一个简单数组

时间:2012-01-26 14:16:02

标签: ruby-on-rails activerecord has-many

考虑这个简单: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

如果有人比我听到的更能解决这个问题,我很乐意听到。

谢谢!

3 个答案:

答案 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的技能,请将其转换为数组并保持良好状态。