从可变数量的数组的产品动态创建对象

时间:2022-10-11 21:18:23

I'm trying to create a Variant from a Product and its associations. The following code works if the product has some associated sides, sizes and options but this is not always the case. If any one of those are not provided then #product produces nil.

我正在尝试从Product及其关联创建Variant。如果产品具有一些关联的边,尺寸和选项,则以下代码有效,但情况并非总是如此。如果没有提供其中任何一个,则#product生成nil。

def self.create_from_product_attrs(product_id, sides, sizes, options)
  sides.product(sizes, options).collect do |side, size, option|
    Variant.create(product_side_id: side.id, product_size_id: size.id, product_option_id: option.id, product_id: product_id)
  end
end

I have also tried:

我也尝试过:

array = [sides, sizes, options]
array.first.product(*array[1..-1]).map(&:flatten).collect do |side, size, option|
  Variant.create(product_side_id: side.id, product_size_id: size.id, product_option_id: option.id, product_id: product_id)
end

in an attempt to exclude any empty values being passed to #product.

试图排除传递给#product的任何空值。

I have had more success with the following but its still failing some tests:

我在以下方面取得了更大的成功,但仍未通过一些测试:

array = [sides, sizes, options]
array.reject! { |c| c.empty? }
if array.empty?
  Variant.create(product_id: product_id)
else
  array.first.product(*array.drop(1)).map(&:flatten).collect do |side, size, option|
    variant = Variant.new
    variant.assign_attributes(product_side_id: side.id) if side.present?
    variant.assign_attributes(product_size_id: size.id) if size.present?
    variant.assign_attributes(product_option_id: option.id) if option.present?
    variant.assign_attributes(product_id: product_id)
    variant.save
  end
end

Updated to include Rspec tests:

更新以包括Rspec测试:

before do
    @product_side = Fabricate(:product_side)
    @product_side_2 = Fabricate(:product_side, name: '2 Sides')
    @product_size = Fabricate(:product_size)
    @product_size_2 = Fabricate(:product_size, name: 'A3')
end

it "should create a product variant when the product is created" do
    @product = Fabricate(:product)
    @product.variants.count.should == 1
end

it "should create 2 variants for a product with 2 sides" do
    @product = Fabricate(:product, product_side_ids: ["#{@product_side.id}", "#{@product_side_2.id}"])
    @product.variants.count.should == 2
end

it "should create 2 variants for a product with 2 sizes" do
    @product = Fabricate(:product, product_size_ids: ["#{@product_size.id}", "#{@product_size_2.id}"])
    @product.variants.count.should == 2
end

it "should create 2 variants for a product with 2 options" do
    @product = Fabricate.build(:product)
    @product_option = Fabricate(:product_option, product_id: @product.id)
    @product_option_2 = Fabricate(:product_option, name: 'None', product_id: @product.id)
    @product.save

    @product.variants.count.should == 2
end

it "should create 4 variants for a product with 2 sides and 2 options" do
    @product = Fabricate.build(:product, product_side_ids: ["#{@product_side.id}", "#{@product_side_2.id}"])
    @product_option = Fabricate(:product_option, product_id: @product.id)
    @product_option_2 = Fabricate(:product_option, name: 'None', product_id: @product.id)
    @product.save

    @product.variants.count.should == 4
end

it "should create 8 variants for a product with 2 sides and 2 options and 2 sizes" do
    @product = Fabricate(:product, product_side_ids: ["#{@product_side.id}", "#{@product_side_2.id}"], product_size_ids: ["#{@product_size.id}", "#{@product_size_2.id}"])
    @product_option = @product.product_options.create(name: 'Rounded', description: 'Add a round edge')
    @product_option_2 = @product.product_options.create(name: 'None', description: 'Nothing')
    @product.save
    @product.variants.count.should == 8
end

1 个解决方案

#1


0  

What you want to do is build an array with a nil element for each empty set, and iterate over the sets. Instead of assigning the id, just assign the object directly (which should work just as well in ActiveRecord).

你想要做的是为每个空集构建一个带有nil元素的数组,并迭代这些集合。不是分配id,而是直接分配对象(在ActiveRecord中应该也能正常工作)。

def self.create_from_product_attrs(product_id, sides, sizes, options)
  sides = [nil] if sides.blank?
  sizes = [nil] if sizes.blank?
  options = [nil] if options.blank?
  sides.product(sizes, options).each do |side, size, option|
    Variant.create(product_id: product_id, product_side: side, product_size: size, product_option: option)
  end
end

#1


0  

What you want to do is build an array with a nil element for each empty set, and iterate over the sets. Instead of assigning the id, just assign the object directly (which should work just as well in ActiveRecord).

你想要做的是为每个空集构建一个带有nil元素的数组,并迭代这些集合。不是分配id,而是直接分配对象(在ActiveRecord中应该也能正常工作)。

def self.create_from_product_attrs(product_id, sides, sizes, options)
  sides = [nil] if sides.blank?
  sizes = [nil] if sizes.blank?
  options = [nil] if options.blank?
  sides.product(sizes, options).each do |side, size, option|
    Variant.create(product_id: product_id, product_side: side, product_size: size, product_option: option)
  end
end