ActiveRecord: обработка списка has_many как простого массива - PullRequest
4 голосов
/ 26 января 2012

Рассмотрим это простое отношение has_many:

class Basket < ActiveRecord::Base
    has_many :apples
    ...
end

class Apple < ActiveRecord::Base
    belongs_to :basket
end

Теперь у меня есть метод в классе Basket, в котором я хочу создать временную копию массива 'apple' и манипулировать временной копией.Для начала я хочу добавить новый элемент во временную копию следующим образом:

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, когда я пытаюсь добавить егона мой временный массив.Вся причина, по которой я создал временный массив, заключается в том, чтобы избежать всего поведения, которое идет с основным массивом, например проверки, вставки базы данных и т. Д.

Тем не менее, я нашел грубую силуЧтобы избежать этой проблемы, создавайте temp_array по одному объекту за раз в цикле for, как показано ниже.Это работает, но это некрасиво.Мне интересно, есть ли более элегантный способ добиться этого.

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 ]

9 голосов
/ 26 января 2012

Проблема в том, что self.apples на самом деле не является массивом - это отношение, которое будет разрешено после применения к нему метода Array / Enumerable. Итак, после этого: temp_array = self.apples даже SQL-запрос не был запущен.

Простое решение для принудительного получения данных и избавления от всего этого поведения Relation - просто использовать метод all:

#create a temporary working copy of the apples array
temp_array = self.apples.all
2 голосов
/ 26 января 2012
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
1 голос
/ 25 июня 2015

Я считаю более логичным использовать self.apples.to_a (= to_array):

По сути, ActiveRecord::Relation - это объект, который расширяет сам Array, то есть он имеет все Array навыки, ноподробнее.

Если вам нужно уменьшить навыки ActiveRecord::Relation, преобразуйте его в массив, и все хорошо.

...