Ruby on Rails Лучшие практики - Большой контроллер против малого контроллера
Мне нужна некоторая информация для лучших практик в Ruby on Rails, особенно с Controller, который должен делать много вещей, поэтому простое действие "show" теперь готово к работе. Я знаю, это не очень хорошо, и у меня есть определенный код в нем.
Вот пример кода:
def show
sound = Sound.find(params[:id])
@xml_path = File.dirname(sound.file.path)
s3 = AWS::S3.new(
:access_key_id => 'XXX',
:secret_access_key => 'XXX')
@url = s3.buckets['dev'].objects[sound.file.path[1..-1]].url_for(:read, :expires => 10*60)
if sound.id_job != 0 && sound.transcript_progress != 100
@response = Savon.client("http://srap.php?wsdl").request(:avance) do
soap.body = {
:Jeton => "abcdef",
:ID_job => sound.id_job,
}
end
@response = @response.to_hash
@progress = @response[:avance][:avancement].to_s.split("#")[1]# ID_job received is formed like "OK#123", we keep "123"
if @progress == "Termine"
sound.transcript_progress = 100
elsif @progress == "ERROR"
flash.now[:alert] = "Oups, il semblerait que le fichier soit illisible, ou qu'il n'y ait rien a ecouter !"
elsif @progress != "Queued"
sound.transcript_progress = @response[:avance_response][:avancement].to_s.split("#")[2].split("%")[0].to_i
end
sound.save
end
if sound.transcript_progress == 100 # If transcription finished
# Get XML File URL on the FTP
@xml_path = Savon.client("http://srap.php?wsdl").request(:donneResultat) do
soap.body = {
:Jeton => "XXX",
:FichierSon => sound.id_job
}
end
# Parse XML Path URL on Kimsufi
@xml_path = @xml_path.to_hash[:donne_resultat_transposition_response][:chemin_fichier].to_s.split("#")[2].to_s.split("/")[5]
# Create local directory (/tmp/sounds) for XML Temp Save
if ! File.directory?(Rails.root.to_s + '/tmp/sounds')
Dir.mkdir(Rails.root.to_s + '/tmp/sounds')
end
# Get XML from FTP
ftp=Net::FTP.new
ftp.connect("ftp.com", 21)
ftp.login("XXX", "XXX")
if ftp.closed?
flash.now[:alert] = "Oups, il semblerait qu'il y ait eu un problème ! Merci d'actualiser la page"
else
ftp.passive = true
ftp.chdir('results')
ftp.getbinaryfile(@xml_path, Rails.root.to_s + '/tmp/sounds/' + @xml_path)
ftp.close
end
# Send XML on S3
s3 = AWS::S3.new(
:access_key_id => 'XXX',
:secret_access_key => 'XXX')
@xml_new = (File.dirname(@sound.file.path) + '/' + File.basename(@xml_path))[1..-1]
s3.buckets['dev'].objects[@xml_new].write(Pathname.new(Rails.root.to_s + '/tmp/sounds/' + @xml_path))
@file = s3.buckets['dev'].objects[@xml_new].read()
end
# A lot of logic again, i've not did it yet
end
Как вы можете видеть, у меня есть много логики здесь, я должен проверить, закончилась ли транскрипция, если нет, обновить progress_bar (@sound.transcript_progress), если да, мне сначала нужно подключиться к мыльному действию, чтобы получить путь XML, затем получите XML через FTP, а затем отправьте его на Amazon S3 (дерьмовое SOAP, я должен повторить все ответы...).
Во всех моих контроллерах действий я должен подключаться по S3 / SOAP / FTP, а не в том же порядке. Поэтому я думаю сделать класс для каждого, как в C++, абстракцию. Я хочу, чтобы все было сделано, мне все равно (как много), как это делается. Но какова лучшая практика с MVC? Я должен сделать новую папку "Класс?" Новый контроллер?
3 ответа
Это скорее подробный комментарий, поскольку он объясняет происхождение вашей дилеммы, но не дает решений.
Проблема на самом деле вызвана неверной интерпретацией MVC, которую популяризирует RoR.
Это сочетание двух факторов, которые вызывают этот взрыв контроллера:
С одной стороны, у вас анемичная модель, потому что вместо реального слоя модели RoR использует коллекцию экземпляров ORM. Причиной этого является то, что Rails изначально создавался как среда для быстрого прототипирования (генерации одноразового кода). И именно прототипирование - это то, в чем лучшая запись. Используя скаффолдинг, вы можете легко генерировать структуры активных записей из существующих баз данных.
Но это приводит к утечке некоторой части бизнес-логики в ваших контроллерах.
С другой стороны у вас есть несуществующее представление. Поскольку целью было создание прототипов, Rails предпочел избавиться от представлений, которые могут фактически содержать логику представления, путем объединения их в контроллеры. Теперь отсутствующие представления были заменены простыми шаблонами, которые просто называются "представлениями".
Это заставляет контроллеры содержать логику представления.
Эти два фактора могут послужить причиной, почему я испытываю соблазн утверждать, что RoR - это даже не инфраструктура MVC. Полученный шаблон на самом деле ближе к Model-View-Presenter. Хотя он был упрощен до такой степени, что начинает нарушать разделение проблем.
Большая часть вашей логики не принадлежит контроллеру. Ответственность контроллеров заключается в том, чтобы связать ввод (HTTP-запросы и их параметры) с выводом (ваши представления). Все остальное - бизнес-логика, которая должна быть реализована в модели - Sound
в твоем случае это выглядит так. Каждый из ваших if
блоки, например, были бы хорошим кандидатом для реализации в качестве метода экземпляра Sound
учебный класс. Если вы обнаружите, что повторно используете код (например, бит хранилища AWS) в различных моделях, реализуйте их в модуле (в разделе lib
) и включить этот модуль в эти модели.
Похоже, что все это должно быть преобразовано в модель (или библиотечный модуль) и разбито на более мелкие функции. Лучшая причина этого заключается в том, что тогда вы можете настроить модульные тесты для индивидуального тестирования небольших деталей. Контроллеру просто необходимо создать экземпляр модели и вернуть данные в браузер.