У меня есть фрагмент кода, который мне действительно может пригодиться с рефакторингом. Мне нужны разные методы для добавления реляционных данных в форму в рельсах. Код взят из http://railscasts.com/episodes/75-complex-forms-part-3, моя проблема в том, что мне нужны методы как для модели материала, так и для модели ответа. Так что мне нужен один и тот же код дважды с заменой «материалов» на «ответы».
Кажется, это нужно решить с помощью динамического программирования? Но у меня нет в этом никакого опыта.
Как это решается?
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





Вы также можете взглянуть на этот сайт:
Если я вас правильно понял, вы хотите иметь те же методы для answers, что и для materials, но с минимальным дублированием кода. Способ сделать это - абстрагироваться от некоторых частных методов, которые будут работать либо для answers, либо для materials, и вызывать их с соответствующей моделью из методов, специфичных для этих моделей. Ниже я привел образец. Обратите внимание, что я ничего не делал с методами 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