用一些动态编程重构?

时间:2008-12-26 13:52:10

标签: ruby-on-rails ruby dynamic metaprogramming

我在这里有一段代码,我真的可以在重构时使用一些帮助。我需要在rails中以表格形式添加关系数据的不同方法。代码取自http://railscasts.com/episodes/75-complex-forms-part-3,我的问题是我需要使用Material模型和Answer模型的方法。所以我需要完全相同的代码两次,“材料”替换为“答案”。

这似乎应该通过一些动态编程来解决?但我对此毫无经验。

这是如何解决的?

after_update :save_materials
after_update :save_answers  

def new_material_attributes=(material_attributes)
  material_attributes.each do |attributes|
    materials.build(attributes)
  end
end

def existing_material_attributes=(material_attributes)
  materials.reject(&:new_record?).each do |material|
    attributes = material_attributes[material.id.to_s]
    if attributes
      material.attributes = attributes
    else
      materials.delete(material)
    end
  end
end

def save_materials
  materials.each do |material|
    material.save(false)
  end
end

2 个答案:

答案 0 :(得分:5)

您可能还想看一下这个网站:

http://refactormycode.com/

答案 1 :(得分:1)

如果我理解正确,您希望answers使用与materials相同的方法,但要复制最少的代码。这样做的方法是抽象一些适用于answersmaterials的私有方法,并使用适用于这些模型的方法的相应模型调用它们。我在下面给出了一个示例。请注意,我没有对save_方法做任何事情,因为我觉得它们足够短,抽象它们实际上并没有节省太多。

after_update :save_materials
after_update :save_answers  

// Public methods

def new_material_attributes=(material_attributes)
  self.new_with_attributes(materials, material_attributes)
end

def new_answer_attributes=(answer_attributes)
  self.new_with_attributes(answers, answer_attributes)
end

def existing_material_attributes=(material_attributes)
  self.existing_with_attributes(materials, material_attributes)
end

def existing_answer_attributes=(answer_attributes)
  self.existing_with_attributes(answers, answer_attributes)
end

def save_materials
  materials.each do |material|
    material.save(false)
  end
end

def save_answers
  answers.each do |answer|
     answer.save(false)
  end
end

// Private methods    

private
def new_with_atttributes(thing,attributes)
    attributes.each do |attribute|
       thing.build(attribute)
    end
end

def existing_with_attributes=(things, attributes)
  things.reject(&:new_record?).each do |thing|
    attrs = attributes[thing.id.to_s]
    if attrs
      thing.attributes = attrs
    else
      things.delete(thing)
    end
  end
end