创建带有条件的嵌套属性

时间:2019-02-23 15:15:22

标签: ruby-on-rails

我有三种型号进货产品尺寸

#Product
  has_many :sizes, as: :sizeable 

#Size
  belongs_to :sizeable, polymorphic: true

restocking.rb

class Restocking < ApplicationRecord
  has_many :sizes, as: :sizeable
  belongs_to :product
  accepts_nested_attributes_for :sizes


  def update_existing_product
    product = self.product
    product.update_attributes(
     price: self.price,
     buying_price: self.buying_price,
    )
    sizes = Size.where(sizeable_id: self.product_id)
    self.sizes.each do |restocking_size|
        sizes.each do |product_size|
          if product_size.size_name == restocking_size.size_name
            product_size.quantity += restocking_size.quantity
            product_size.save
         end
        end
      end
    end
  end

因此update_existing_product方法会更新现有尺寸的价格和数量...

如果找到类似的size_name,则会更新现有的尺寸数量,否则会创建一个新的尺寸... 我无法正确创建新尺寸...

我应该使用这种Size.create方法,但是当我将其放在循环中时,它会多次创建相同的大小。

Size.create!(
    sizeable_id: self.product_id,
    sizeable_type: "Product",
    size_name: restocking_size.size_name,
    quantity: restocking_size.quantity,
)

1 个答案:

答案 0 :(得分:1)

由于构建循环的方式,

Size被多次创建。

修正代码如下:

self.sizes.each do |restocking_size|
  if (existing_size = sizes.find{|s| s.size_name == restocking_size.size_name })
    existing_size.tap{|s| s.quantity += restocking_size.quantity }.save!
  else
    # no existing, here goes create
  end
end

但是请记住,如果此代码恰好在其他一些代码更新相同数据的同时运行,则在应用程序级别处理此问题可能会导致争用情况。 例如:

  1. 我们有10个大小为B的项目A
  2. 再休息5个
  3. 代码运行,获取sizesquantity中有10个
  4. 此刻,某人购买了一件这样大小的物品,还剩9件,并已写入数据库
  5. 补充库存继续运行-将5加到10,将15写入db
  6. quantity是15,而一件商品已售出

可以通过在每个更新计数器的地方使用record#with_lock{ here update happens }来避免(但是这会重新加载记录,对于大容量而言可能效率不高)。