簡體   English   中英

Ruby on Rails:數據庫字段的值取決於如何訪問?

[英]Ruby on Rails: Value of database field depends on how accessed?

我有一個表現出奇怪行為的電子商務應用程序。 該產品是培訓課程。 學生為各個班級創建預訂,這些預訂將作為訂單項添加到購物車中。 在某個時候,訂單被創建並支付,這時我需要遍歷每個預訂,並更新“已支付”屬性。 所以這是數據庫的構造...

1) Class has_many Reservations
2) Reservation belongs_to class, and has_one line_item (and has a decimal :paid attribute)
3) Line_item belongs_to reservation, and belongs_to cart
4) Cart has_many line_items, and has_one order

因此,當學生創建訂單時,將執行信用卡交易,如果成功,我想生成收據並將其通過電子郵件發送給學生。

最初,在我的OrdersController#create方法中看起來像這樣...

def create
  @cart = current_cart #retrieves the cart 
  @order = @cart.build_order(params[:order])
  # snip saving order and purchase transaction
  # I would then iterate over the line-items with
  @cart.line_items.each { |li| li.reservation.update_attribute(:paid, li.reservation.fee)}

但是,此時我發現,付費屬性的值將取決於line_item的訪問方式。 如果我通過...訪問

@cart.line_items.each {|li| li.reservation.paid }

值將被設置。 但是,如果使用過...

@order.cart.line_items.each {|li| li.reservation.paid }

該值將為零。 (但是它正在訪問適當的reservation.id)

然后我發現,如果我更改將付費屬性設置為以下內容的行...

  @order.cart.line_items.each { |li| li.reservation.update_attribute(:paid, li.reservation.fee)}

以上任一訪問將返回正確的值。

所以我想我的問題是,設置:paid屬性與有什么區別

@cart.line_items.each ...

@order.cart.line_times.each ...

基於下面的評論,我將迭代移入了Cart模型。 現在有

def paid_deposit!
  self.line_items.includes(:reservation).each do |li|
    li.reservation.update_attribute(:paid, li.reservation.deposit)
  end
end

但是,存在相同的問題控制器具有以下代碼...

@cart.paid_deposit!
@cart.line_items.each {|li| logger.debug "Cart: Res: #{li.reservation.id}, Paid: #{li.reservation.paid}" }
@order.cart.line_items.each {|li| logger.debug "Order: Res: #{li.reservation.id}, Paid: #{li.reservation.paid}" }

結果日志是...

Reservation Load (0.3ms)  SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`id` IN (346, 347, 348)
(0.2ms)  BEGIN
(0.2ms)  UPDATE `reservations` SET `paid` = 40.0, `updated_at` = '2012-02-05 22:12:36' WHERE `reservations`.`id` = 346
(0.4ms)  COMMIT
(0.1ms)  BEGIN
(0.1ms)  UPDATE `reservations` SET `paid` = 40.0, `updated_at` = '2012-02-05 22:12:36' WHERE `reservations`.`id` = 347
(0.6ms)  COMMIT
(0.1ms)  BEGIN
(0.1ms)  UPDATE `reservations` SET `paid` = 25.0, `updated_at` = '2012-02-05 22:12:36' WHERE `reservations`.`id` = 348
(0.3ms)  COMMIT
LineItem Load (0.1ms)  SELECT `line_items`.* FROM `line_items` WHERE `line_items`.`cart_id` = 24
Reservation Load (0.2ms)  SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`id` = 346 LIMIT 1
Cart: Res: 346, Paid: 40.0
Reservation Load (0.1ms)  SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`id` = 347 LIMIT 1
Cart: Res: 347, Paid: 40.0
Reservation Load (0.1ms)  SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`id` = 348 LIMIT 1
Cart: Res: 348, Paid: 25.0
Order: Res: 346, Paid: 0.0
Order: Res: 347, Paid: 0.0
Order: Res: 348, Paid: 0.0

可以看出,從購物車中引用付款金額會獲得正確的值,而從Order中執行相同的操作就不會。 顯然使用緩存的值? 它不訪問數據庫。

這是一種更新這樣的事情的可怕方法。 我希望您有一個很好的單元測試或功能測試來證明這種損壞的行為,以便可以確定正確時將其修復。

您可能應該制作一個模型方法來幫助簡化此類事情。 由於無法從交互式控制台輕松訪問控制器環境,因此在控制器中進行了大量繁重的工作使測試變得困難。

我不知道的是,如何調用諸如paid的訪問器方法在each循環中有什么用處。 那應該返回一個數字,而不是設置任何東西。 update_attribute版本應該可以工作,因為它實際上正在更改數據。

您可以做的是將其推入模型,並創建一個執行以下操作的方法:

class Cart < ActiveRecord::Base
  def paid!
    self.line_items.include(:reservation).each do |li|
      li.update_attribute(:paid, li.reservation.fee)
    end
  end
end

如果您可以在數據庫中完成所有操作,則速度可能會更快:

class Cart < ActiveRecord::Base
  def paid!
    self.line_items.include(:reservation).update_all(
      'paid=reservations.fee'
    )
  end
end

通常,我只是尋找一些方法來避開模型,如果它們只是扭曲那些不受驗證檢查的字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM