Con la crescita dell'app, certe operazioni non appartengono a nessun model in particolare: coinvolgono più oggetti, chiamate esterne, passaggi. Metterle nel controller lo gonfia; metterle in un model lo snatura. La risposta è un service object.
class SyncLaunches
def initialize(source: LaunchLibrary)
@source = source
end
def call
@source.upcoming.map do |data|
Launch.upsert(data, unique_by: :name)
end
end
end
# nel controller, una riga:
SyncLaunches.new.call
Un service object è una semplice classe Ruby con un metodo pubblico (di solito call) che fa una cosa. Riceve le dipendenze nel costruttore (comodo per i test), incapsula il flusso, restituisce un risultato.
Vantaggi: controller magri, logica testabile in isolamento, nomi che raccontano cosa fa l'app (SyncLaunches, RegisterUser, ChargeOrder). Non è magia di Rails: è solo buon design a oggetti applicato con disciplina.