Rails push в массив сохраняет объект
У меня есть интересная проблема. Я использую Ruby 1.9.2 и Rails 3.1.3.
У меня есть 2 модели, для упрощения пусть говорят клиенты и магазины.
В магазинах много клиентов, а клиент принадлежит магазину.
Я пытаюсь собрать всех клиентов для магазина и создать место для еще нескольких, которые я могу заполнить значениями позже. Вместо этого клиент .save вызывается, когда я этого не ожидаю.
store = Store.find(1)
customers_array = store.customers
random_array = Array.new
customers_count = customers_array.count + 1
(customers_count..2).each do |i|
customer = Customer.new
c.id = "#{i}000000000000"
random_array << customer # this line doesn't call customer.save
customers_array << customer # this line calls customer.save when store has customers
end
По какой-то причине, когда клиент вставляется в массив, вызывается customer.save.
Это не происходит, если вы нажимаете на массив, это простой массив, а не отношение.
Я нашел обходной путь, но мне все еще интересно, почему это происходит.
Обходной путь:
store = Store.find(1)
initial_customers_array = store.customers
additional_customers_array = Array.new
customers_count = initial_customers_array.count + 1
(customers_count..2).each do |i|
customer = Customer.new
c.id = "#{i}000000000000"
additional_customers_array << customer
end
customers_array = initial_customers_array + additional_customers_array
Ответы
Ответ 1
<<
является псевдонимом для push
который в ActiveRecord::Associations::CollectionProxy
вызывает concat
который вызывает concat_records
где вы видите вставку.
Итак, с существующей записью (сохраняющейся в базе данных) запуск <<
или .push
будет вставлять записи в коллекцию, при необходимости сохраняя их в базе данных. Вызов <<
в массиве, а не в коллекции записей, как вы делаете в
random_array << customer
вызывает Ruby <<
метод Array, а не эквивалент AR (как вы обнаружили, в этом случае не выполняется сохранение).
Изменить: Чтобы быть ясным, обходной путь, который вы нашли, более или менее относится к тому, как я обычно обрабатываю ситуацию, с которой вы имеете дело; мой ответ больше посвящен тому, почему <<
имеет такое поведение.
Ответ 2
Другой способ: изменить вторую строку (исходного кода) на:
customers_array = store.customers.to_a
Это связывает активную ассоциацию записи с реальным объектом массива, поэтому метод <<
будет обычным методом перемещения массива #.