如何在Rails模型类上正确格式化实例变量

时间:2017-03-07 14:12:49

标签: ruby-on-rails ruby

我有一个表材质,has_one与MaterialCosts相关,has_one与MaterialCharges相关。它们都属于材料,在删除或记录材料时应dependent: :destroy

我不确定如何构造Material类。必须使用每个Material实例的两个属性来计算MaterialCosts和MaterialCharges中的字段。这些是cost_per_sqmink_per_sqmfactor是Material中的一个字段,也用于MaterialCharges。我是否需要在Material中初始化它们,以便为create方法使用实例变量?或者是attr_accessor所需要的全部内容?

我知道代码需要重构,但是当我尝试播种数据时,我也遇到了这个错误:

NoMethodError: undefined method `[]' for nil:NilClass on line 26 seeds.rb

第26行种子.rb:

Material.create({ product_name: "Novajet Art 255gsm", guk_name: "none", roll_width_in: 44, roll_length_m: 30, factor: 7, rounded_sale_price: 71, list_price: 240.00, cost_per_sqm: 7.16, ink_per_sqm: 3, supplier_discount: 0, sell_per_sqm: 71.11 })

这是我的代码:

  class Material < ApplicationRecord

  has_and_belongs_to_many :job_entries
  has_one :material_cost,  dependent: :destroy
  has_one :material_charge, dependent:  :destroy

  attr_accessor :cost_per_sqm, :ink_per_sqm, :factor

  def initialize(options)
    @cost_per_sqm = options['cost_per_sqm'].to_f
    @ink_per_sqm = options['ink_per_sqm'].to_f
    @factor = options['@factor'].to_f
    @total_cost = @cost_per_sqm * @ink_per_sqm
  end


  after_create :set_material_cost, :set_material_charge


  A4_FACTOR = 0.0626514876
  A3_FACTOR = 0.124548139
  A2_FACTOR = 0.249096276
  A1_FACTOR = 0.499702226
  B0_FACTOR = 1.41585523
  B1_FACTOR = 0.706656651
  B2_FACTOR = 0.353328326
  B3_FACTOR = 0.176664163
  B4_FACTOR = 0.0878836952

  private



  def set_material_cost
    @material_cost = self.create_material_cost(
    cost_a4: @total_cost * A4_FACTOR,
    cost_a3: @total_cost * A3_FACTOR,
    cost_a2: @total_cost * A2_FACTOR,
    cost_a1: @total_cost * A1_FACTOR,
    cost_b0: @total_cost * B0_FACTOR,
    cost_b1: @total_cost * B1_FACTOR,
    cost_b2: @total_cost * B2_FACTOR,
    cost_b3: @total_cost * B3_FACTOR,
    cost_b4: @total_cost * B4_FACTOR
    )
  end



def set_material_charge
    @material_charge = self.create_material_charge(
    sell_a4: @total_cost * A4_FACTOR * @factor,
    sell_a3: @total_cost * A3_FACTOR * @factor,
    sell_a2: @total_cost * A2_FACTOR * @factor,
    sell_a1: @total_cost * A1_FACTOR * @factor,
    sell_b0: @total_cost * B0_FACTOR * @factor,
    sell_b1: @total_cost * B1_FACTOR * @factor,
    sell_b2: @total_cost * B2_FACTOR * @factor,
    sell_b3: @total_cost * B3_FACTOR * @factor,
    sell_b4: @total_cost * B4_FACTOR * @factor
    )

  end


    end

    class MaterialCost < ApplicationRecord
      belongs_to :material
    end

    class MaterialCharge < ApplicationRecord
      belongs_to :material
    end

这是代码应该是什么样的?

1 个答案:

答案 0 :(得分:1)

如曹提到的那样,请勿覆盖initialize,但如果有,则必须拨打super

# use '*args' so super can use any arguments to 'new'
def initialize(*args)
  # as first line so Rails will do it's "magic" before yours
  super

  # these have got values by Rails (in super) IF you have them
  # in the call to 'new'
  @cost_per_sqm = @cost_per_sqm.to_f
  @ink_per_sqm  = @ink_per_sqm.to_f
  # (you have forgot this as attr_accessor?)
  @factor       = @factor.to_f
  @total_cost   = @cost_per_sqm * @ink_per_sqm
end

但我不想使用initialize,而是使用其他方法

# instead of overriding 'initialize'
def init_after_create
  return if @total_cost
  # these have got values by Rails (in new) IF you have them
  # in the call to 'new'
  @cost_per_sqm = @cost_per_sqm.to_f
  @ink_per_sqm  = @ink_per_sqm.to_f
  # (you have forgot this as attr_accessor?)
  @factor       = @factor.to_f
  @total_cost   = @cost_per_sqm * @ink_per_sqm
end

def set_material_cost
  init_after_create
  @material_cost = self.create_material_cost(
  cost_a4: @total_cost * A4_FACTOR,
  cost_a3: @total_cost * A3_FACTOR,
  ....
end

def set_material_charge
  init_after_create
  @material_charge = self.create_material_charge(
  sell_a4: @total_cost * A4_FACTOR * @factor,
  sell_a3: @total_cost * A3_FACTOR * @factor,
  ...
end

提示,如果您在方法调用中有Hash作为最后一个参数,或者在Array中您不必使用{ ... }

# example method
def some_method(options)
  ...
end
some_method(xxx: 1, yyy: 2)

# example array
arr = [ 1, 2, xxx: 1, yyy: 2 ]
#=> [1, 2, {:xxx=>1, :yyy=>2}]