#ruby-on-rails #caching
#ruby-on-rails #кэширование
Вопрос:
У Order
has_many
OrderItems
. So OrderItem
есть order_id
поле.
Как изменить, к какому Order
OrderItem
элементу принадлежит? Такой, который вы можете вызвать @order.order_items
.
Я попытался изменить order_id
of OrderItem
, но это не работает. Или, по крайней мере, он не отображается при вызове @order.order_items
.
Редактировать: консоль
~/practice/dinner_dash >> rails c --sandbox
Loading development environment in sandbox (Rails 4.0.3)
Any modifications you make will be rolled back on exit
2.0.0-p451 :001 > order1 = Order.first
Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT 1
=> #<Order id: 2, status: "Unsubmitted.", user_id: 1, created_at: "2014-06-28 16:21:24", updated_at: "2014-06-28 16:21:24">
2.0.0-p451 :002 > order1.order_items.each { |order_item| puts order_item }
OrderItem Load (2.5ms) SELECT "order_items".* FROM "order_items" WHERE "order_items"."order_id" = ? [["order_id", 2]]
#<OrderItem:0x007f9dd34d0710>
#<OrderItem:0x007f9dd35b9550>
#<OrderItem:0x007f9dd35b8fd8>
=> [#<OrderItem id: 8, quantity: 5, item_id: 2, order_id: 2, created_at: "2014-06-28 16:30:33", updated_at: "2014-06-29 02:06:17">, #<OrderItem id: 9, quantity: 2, item_id: 3, order_id: 2, created_at: "2014-06-28 16:30:45", updated_at: "2014-06-28 16:56:41">, #<OrderItem id: 15, quantity: 1, item_id: 4, order_id: 2, created_at: "2014-06-28 17:42:17", updated_at: "2014-06-28 17:42:17">]
2.0.0-p451 :003 > order2 = Order.last
Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" DESC LIMIT 1
=> #<Order id: 15, status: "Unsubmitted.", user_id: 2, created_at: "2014-06-28 17:38:08", updated_at: "2014-06-28 17:40:11">
2.0.0-p451 :004 > order2.order_items.first.order = order1
OrderItem Load (0.3ms) SELECT "order_items".* FROM "order_items" WHERE "order_items"."order_id" = ? ORDER BY "order_items"."id" ASC LIMIT 1 [["order_id", 15]]
=> #<Order id: 2, status: "Unsubmitted.", user_id: 1, created_at: "2014-06-28 16:21:24", updated_at: "2014-06-28 16:21:24">
2.0.0-p451 :005 > order1.order_items.each { |order_item| puts order_item }
#<OrderItem:0x007f9dd34d0710>
#<OrderItem:0x007f9dd35b9550>
#<OrderItem:0x007f9dd35b8fd8>
=> [#<OrderItem id: 8, quantity: 5, item_id: 2, order_id: 2, created_at: "2014-06-28 16:30:33", updated_at: "2014-06-29 02:06:17">, #<OrderItem id: 9, quantity: 2, item_id: 3, order_id: 2, created_at: "2014-06-28 16:30:45", updated_at: "2014-06-28 16:56:41">, #<OrderItem id: 15, quantity: 1, item_id: 4, order_id: 2, created_at: "2014-06-28 17:42:17", updated_at: "2014-06-28 17:42:17">]
2.0.0-p451 :006 >
Редактировать: реальная проблема
Я думаю, что реальная проблема заключается в том, что @order
возвращаемый by load_order
кэшируется. Итак, вызывается второй раз load_order
, он возвращает старое @order
, которое было кэшировано в памяти. Я не уверен, как это исправить.
application_controller.rb
def load_order
@order = Order.find_or_initialize_by_id(session[:order_id], status: 'Unsubmitted.', user_id: session[:user_id])
if @order.new_record?
@order.save!
session[:order_id] = @order.id
end
end
sessions_controller.rb
def create
user = login(params[:email], params[:password], params[:remember_me])
if user
load_order
@order.update(user_id: user.id)
merge_orders
session[:order_id] = Order.find_by_user_id(user.id).id if Order.find_by_user_id(user.id)
load_order
redirect_back_or_to root_path, notice: 'Logged in!'
else
flash.now.alert = 'Email or password was invalid.'
render :new
end
end
Редактировать: код, который не работает
Те order_items
, которые распечатываются каждый раз, одинаковы. Однако order_item.order_id
он изменяется.
def merge_orders
orders = Order.all
user_orders = {}
orders.each do |order|
if user_orders[order.user_id] == nil
user_orders[order.user_id] = order
else
original_order = user_orders[order.user_id]
original_order.order_items.each do |order_item|
item = Item.find_by_id(order_item.item_id)
puts "nnn#{item.name} x #{order_item.quantity}nnn"
end
current_order = order
# assign order_id of current_order to original_order
current_order.order_items.each do |order_item|
puts "order_item.order_id: #{order_item.order_id}"
order_item.update(order_id: original_order.id)
puts "order_item.order_id: #{order_item.order_id}"
end
original_order.order_items.each do |order_item|
item = Item.find_by_id(order_item.item_id)
puts "nnn#{item.name} x #{order_item.quantity}nnn"
end
# delete current_order
current_order.destroy
puts "nnn"
end
end
end
order.rb
class Order < ActiveRecord::Base
belongs_to :user
has_many :order_items, dependent: :destroy
validates_associated :order_items
end
order_item.rb
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
validates_presence_of :order_id, :item_id, :quantity
validates :quantity, numericality: { only_integer: true, greater_than: 0 }
end
Комментарии:
1. Показать вам модели и код, которые не работают.
Ответ №1:
Как изменить, к какому порядку относится элемент OrderItem?
Самое простое объяснение — изменить order_id
эту запись. Другого способа просто нет, если, конечно, у вас нет нескольких записей, связанных с order
—
Слияние
Я думаю, что ваша проблема связана с вашей merge
функциональностью
Я не понимаю, что вы с этим делаете — похоже, вы выводите item
x quantity
или что-то в этом роде — если вы хотите показать содержимое определенного порядка, вам лучше всего использовать для этого код контроллера:
#app/controllers/orders_controller.rb
Class OrdersController < ApplicationController
def index
# loop through orders amp; create instance variable to output
end
end
Если вы пытаетесь установить current_order
, вы, вероятно, захотите использовать модель на основе сеанса, которая позволит вам сохранять current_order
объект по мере необходимости
-
Как правило, вы никогда не должны напрямую выводить данные с помощью Rails — ваше использование
puts
в основном будет выводить определенные данные, которые не входят в компетенцию MVC -
Рассматривали ли вы возможность изменения вашей
OrderItem
модели на justItem
? Это будет намного менее подробным, когда вы ссылаетесь на него ->@order.items
Комментарии:
1. Обновление order_id — не единственный способ. Пожалуйста, обратитесь к ссылке rails guides для belongs_to: guides.rubyonrails.org /…
2. Извините, вы меня неправильно поняли. Я имел в виду с точки зрения ядра — обновление
order_id
в базе данных — единственный способ фундаментально изменить ассоциацию. Как вы это делаете программно, это другой вопрос3. @RichPeck
puts
Инструкции предназначены только для отладки. Что я пытаюсь сделать вmerge_orders
: если есть два одинаковых заказаuser_id
, присвоитеorder_id
s второго порядка исходному порядку.4. @RichPeck Я думаю, что я понял проблему, но не могу понять, как ее исправить. См. Редактирование вопроса.
5. Как я уже сказал в своем ответе, order.reload
Ответ №2:
Изменение order_id элемента OrderItem и его сохранение должны работать. Вы также можете сделать это:
order_item.order = a_different_order
Поскольку эти данные могут быть кэшированы в памяти, чтобы увидеть это влияние на исходный порядок, вам, возможно, придется сделать:
original_order.reload.order_items
Вы также можете проверить другой другой способ, выполнив:
order_item.reload.order
ps. Вы также должны проверить awesome_print gem, чтобы распечатать это на консоли.
pps. Вы должны делать это в тесте 🙂
Вот пример из моей консоли, где ответ принадлежит пользователю
1.8.7-p352 :003 > a = Answer.last
1.8.7-p352 :005 > a.user_id
=> 4212
1.8.7-p352 :006 > old_user = a.user
1.8.7-p352 :007 > a.user = User.last
1.8.7-p352 :008 > a.user_id
=> 7290
1.8.7-p352 :009 > a.user = old_user
1.8.7-p352 :010 > a.user_id
=> 4212
1.8.7-p352 :016 > a.changed?
=> true
1.8.7-p352 :017 > a.save
SQL (7.1ms) BEGIN
AREL (5.1ms) UPDATE `answers` SET `updated_at` = '2014-06-29 17:39:30', `user_id` = 7290 WHERE `answers`.`id` = 21
SQL (0.4ms) COMMIT
=> true
1.8.7-p352 :018 > a.changed?
=> false
Комментарии:
1. Насколько я понимаю, вызов
update
должен сохранить его. Это правда?original_order.reload.order_items
сейчас выводит правильные вещи, но в моем приложении они по-прежнему не работают (когда я вхожу в систему, не отображается, что порядок обновляется).2. Я думаю, что я понял проблему, но не знаю, как ее исправить. См. Редактирование вопроса.
3. Итак, что я понял из этого, так это то, что я должен делать
order_item.order = original_order
вместоorder_item.update(order_id: original_order.id)
. Но это не работает.original_order.reload.order_items
Последующий вызов также ничего не делает.4. Два приведенных выше метода эквивалентны. Вам нужно упростить свою ситуацию, чтобы выяснить, что вы делаете неправильно. Я не понимаю, как вы обрабатываете изменение поля, это проблема. Сделайте это в консоли и опубликуйте свой код, как я это сделал.
5. Ps, очевидно, вам нужно сохранить свою модель. Добавил этот бит выше.