2012-01-26 3 views
4

Рассмотрим простой: has_many отношения:ActiveRecord: лечение списка has_many как простой массив

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

class Apple < ActiveRecord::Base 
    belongs_to :basket 
end 

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

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 

Когда я делаю это, я считаю, что Validate процедура вызывается на временном объекте 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 

Если у кого-нибудь есть лучшее решение этой проблемы, чем то, что я слышал, я бы хотел его услышать.

Спасибо!

ответ

9

Проблема в том, что 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 
+0

Это сделало. Спасибо! – Denis

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 
1

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

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

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

+0

именно то, что мне нужно, спасибо! –

Смежные вопросы