2009-11-07 11 views
5

Ho un'app che modella una casa. La casa ha molte stanze, stanze con molte luci e piccoli elettrodomestici, ecc. Ho anche un controller chiamato Calcolatrice, ovvero l'accesso all'app. I dati vengono aggiunti alla casa (e alle sue stanze) utilizzando il controller Calcolatrice. Quindi viene generato un rapporto, che si trova in app/views/calculator/report.html.erb.Dove dovrebbe andare la logica di calcolo in un'app Rails?

La mia domanda è dove dovrebbero andare tutti i calcoli e la logica per il rapporto? Attualmente ho tutto nella vista, con alcune cose in calculator_helper. Normalmente questo andrebbe nel modello, giusto? Ma il calcolatore non ha un modello che è stato generato. Qual è lo standard per questo?

Ecco il controller della calcolatrice.

class CalculatorController < ApplicationController 
    def index 
    end 

    def save_house 
    @house = House.new(params[:house]) 
    respond_to do |format| 
     if @house.save 
     format.html { render :action => 'add_rooms', :id => @house } 
     format.xml { render :xml => @house, :status => :created, :location => @house } 
     else 
     format.html { render :action => 'index' } 
     format.xml { render :xml => @house.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    def add_rooms 
    @house = House.find(params[:id]) 
    @rooms = Room.find_by_house_id(@house.id) 

    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before adding rooms" 
    redirect_to :action => 'index' 
    end 

    def add_room 
    @room = Room.new(params[:room]) 
    @house = @room.house 

    respond_to do |format| 
     if @room.save 
     flash[:notice] = "Room \"#{@room.name}\" was successfully added." 
     format.html { render :action => 'add_rooms' } 
     format.xml { render :xml => @room, :status => :created, :location => @room } 
     else 
     format.html { render :action => 'add_rooms' } 
     format.xml { render :xml => @room.errors, :status => :unprocessable_entity } 
     end 
    end 
    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before adding a room" 
    redirect_to :action => 'index' 
    end 

    def report 
    flash[:notice] = nil 
    @house = House.find(params[:id]) 
    @rooms = Room.find_by_house_id(@house.id) 
    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before generating a report" 
    redirect_to :action => 'index' 
    end 
end 
+0

Mostraci la tua classe di Calcolatore. –

+0

Mi piace la risposta di James. Un'altra domanda che penso dovresti chiederti è perché ti stai allontanando dalla convenzione: perché il controller della calcolatrice gestisce cose che apparentemente appartengono al controller House? Non sto dicendo che tu stia sbagliando, sto solo dicendo che vale la pena di riflettere. –

+0

Buon punto, Andy. Ryan, prendi i MODELLI prima di iniziare a preoccuparti dei controller e delle visualizzazioni. Utilizzando questo approccio, potresti scoprire che il luogo corretto per tutti i calcoli è il modello di casa. –

risposta

0

Tutto dipende dal tipo di dati che si stanno creando. Come si presenta il controller della calcolatrice?

È possibile creare classi personalizzate in/lib e utilizzarle nei propri modelli, che può essere un buon modo per separare la logica dal controller/helper. C'è una ragione per cui non potresti mettere un po 'di logica nei modelli?

+0

calculator_controller salva i dati e sposta l'utente alla pagina successiva che consente loro di inserire più informazioni. I modelli stanno facendo la convalida, ma questo è tutto. I calcoli che vengono eseguiti sono principalmente calcoli numerici basati sui parametri di casa e stanza. Ho provato a creare un modello per calcolatrice, ma non riesco ad accedere alle variabili dalla vista. Dovrei fare allora tutte le variabili globali? – Ryan

1

Vorrei creare una classe in RAILS_ROOT/lib/chiamata, ad esempio Calcolatrice e inserire il codice.

Le classi in/lib/devono essere caricate e disponibili ovunque nella tua app.

È anche possibile creare un oggetto rubino semplice in/app/models /. Non c'è alcun motivo che tutti debbano ereditare da ActiveRecord :: Base

+0

Ho creato un file calculator.rb in app/modelli che non ereditano da ActiveRecord. Tuttavia, quando sposto il mio codice su quel file non posso più accedervi dalla vista. Suppongo che sia perché ho fatto tutto con variabili locali. Qual è il modo migliore per risolvere questo problema? Ho provato a cambiarli in variabili globali, ma non sembra essere di aiuto. – Ryan

+0

Inserendo i metodi nei modelli, anziché una classe in lib /, si lega meglio la logica ai dati sottostanti. Inoltre, ha il netto vantaggio di non soffrire di questo problema relativo alle variabili di istanza poiché è possibile chiamare i metodi sulle istanze dei modelli che si stanno già gestendo nel controller e nelle viste. Il codice di allevamento in lib/ha più senso se è utilizzato da più classi nella base di codice, come un modulo Mixin, o è qualcosa che si sta rifondando in un progetto/plugin sidecar riutilizzabile. Se la logica fa parte della base di codici, tienila con il tuo codice principale. –

5

Ci sono alcuni modi per accedervi, ma la logica certamente non appartiene alla vista. I vari modelli sono associati tra loro in una gerarchia chiara con la parte superiore della gerarchia come modello della casa, se sto leggendo correttamente la descrizione. Stando così le cose, aggiungerei un metodo appropriato di set di metodi al modello di House che potrebbe essere composto da chiamate a metodi di calcolo nei modelli Room associati a una determinata istanza di House e in basso alla linea di associazione. In questo modo, il calcolo pertinente può essere eseguito ad ogni livello e componendo uno o più metodi a livello di modello di casa è possibile avere un modo pulito, espressivo e gestibile per gestire i calcoli.

Una cosa da fare, inoltre, sarebbe assicurarsi che tutti i calcoli che possono essere eseguiti dal DB sono. Ad esempio, se esiste un calcolo che un modello Room può eseguire semplicemente interrogando i propri dati, spingere con tutti i mezzi che il carico computazionale al DB utilizza la capacità di ActiveRecord di invocare tale logica di calcolo di livello inferiore. Controlla il API docs per i dettagli.

Vorrei osservare con molta attenzione la logica che si desidera e vedere come può essere inserito nel modello poiché è probabilmente il luogo a cui appartiene, vicino ai dati effettivi dei calcoli e all'interno delle strutture di classe che rappresentano tali dati specificamente; Non creerei un modello solo per gestire la logica di calcolo, a meno che non sia davvero necessario archiviare i calcoli in modo persistente per qualche motivo.

1

Ok, ora posso vedere il codice pubblicato. Vedo che calcolatrice_controller non ha in realtà alcun calcolo, sono nelle viste? Prova questo approccio:

  1. Scrivi un test che imposta un oggetto che restituirà i risultati necessari per tornare all'utente della pagina Web, in base a una casa, stanze o qualsiasi altra cosa di cui ha bisogno.
  2. Costruire un modello (nei modelli) per eseguire tale passaggio di prova.
  3. Modificare il codice del controller in alto per utilizzare il nuovo modello di calcolatrice
  4. Modificare i test del controller in modo che anch'essi passino. Questi test, ovviamente, non hanno bisogno di testare alcuna logica di business.

La mia prima respose:

Se la logica di business è abbastanza semplice e utilizzato solo dietro questo web app, quindi si può mettere nella cartella app/modelli.

class MyCoolClass 
    def initialize(clues) 
    @other_things = OtherThing.all 
    end 
    def do_cool_thing; end 
    def calculate_coolness 
    @other_things.length 
    end 
end 

Poi nel controller, creare un'istanza del modello

def index 
    @mcc = MyCoolClass "A clue as to what I want" 
    render 
end 

Poi nei template è possibile accedervi

<%=h @mcc.calculate_coolness %> 

noti che @other_things è un instance__variable di MyCoolClass e generalmente non accessibile ai modelli senza definizione dei metodi di accesso

+0

Mi piace costruire modelli come questo quando la logica inizia a ingombrare il modello AR. –

Problemi correlati