Refactoring with some dynamic programming?

I have a piece of code that I could actually use through refactoring. I need different methods to add relational data to a form in rails. The code is taken from http://railscasts.com/episodes/75-complex-forms-part-3 , my problem is that I need to have methods for both the Material model and the Answer model. So I need the same code twice, replacing "materials" with "answers".

Seems like it needs to be solved with some dynamic programming? But I have no experience with that.

How is this resolved?

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

      

0


source to share


2 answers


You can also look at this site:



http://refactormycode.com/

+5


source


If you read it right, you want to have the same methods for answers

as for materials

, but duplicate the least code. The way to do this is to abstract some private methods that will either work for answers

or materials

and call them a suitable model from the methods specific to those models. I have provided a sample below. Note that I didn't do anything with the methods save_

because I felt they were short enough that abstracting them really didn't save much.



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

      

+1


source







All Articles