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

时间:2014-01-17 12:13:16

标签: ruby-on-rails ruby arrays

我正在尝试从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

我也尝试过:

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

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

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

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

更新以包含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 个答案:

答案 0 :(得分:0)

您要做的是为每个空集构建一个带有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