2009-11-07 15 views
5

Mam aplikację, która modeluje dom. Dom ma wiele pokojów, pokoi ma wiele świateł i małych urządzeń, itp. Posiadam również kontroler o nazwie Kalkulator, w ten sposób uzyskuje się dostęp do aplikacji. Dane są dodawane do domu (i jego pomieszczeń) za pomocą kontrolera kalkulatora. Następnie generowany jest raport, który znajduje się w app/views/calculator/report.html.erb.Gdzie powinna znajdować się logika obliczeń w aplikacji Rails?

Moje pytanie brzmi: gdzie powinny zostać wykonane wszystkie obliczenia i logika raportu? Obecnie mam to wszystko w widoku, z niektórymi rzeczy w calculator_helper. Normalnie miałoby to miejsce w modelu, prawda? Ale Kalkulator nie ma wygenerowanego modelu. Jaki jest standard w tym?

Oto kalkulator kalkulatora.

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

Pokaż nam swoją klasę kalkulatora. –

+0

Podoba mi się odpowiedź Jamesa. Kolejnym pytaniem, które powinieneś sobie zadać, jest to, dlaczego rezygnujesz z konwencji - dlaczego kontroler kalkulatora obsługuje rzeczy, które z pozoru należą do kontrolera House'a? Nie mówię, że robisz to źle, po prostu mówię, że warto się zastanowić. –

+0

Dobra uwaga, Andy. Ryan, weź MODELE, zanim zaczniesz się martwić kontrolerami i widokami. Dzięki temu podejściu odkryjesz, że właściwym miejscem do wszystkich obliczeń jest model House. –

Odpowiedz

0

Wszystko zależy od rodzaju danych, które tworzysz. Jak wygląda kontroler kalkulatora?

Możesz tworzyć własne klasy w/lib i używać ich w swoich modelach, co może być dobrym sposobem na oddzielenie logiki od kontrolera/pomocników. Czy jest jakiś powód, dla którego nie można umieścić logiki w modelach?

+0

calculator_controller zapisuje dane i przenosi użytkownika do następnej strony, która pozwala im wprowadzić więcej informacji. Modele dokonują sprawdzania poprawności, ale to już wszystko. Obliczenia, które są wykonywane, to głównie obliczenia liczbowe na podstawie parametrów domu i pomieszczenia. Próbowałem stworzyć model kalkulatora, ale nie mogę uzyskać dostępu do zmiennych z widoku. Czy musiałbym wtedy wprowadzić wszystkie zmienne globalne? – Ryan

1

Utworzę klasę w RAILS_ROOT/lib/wywołaną, na przykład, Kalkulator i umieściłem tam kod.

Klasy w/lib/powinny być załadowane i dostępne w dowolnym miejscu aplikacji.

Możesz także utworzyć zwykły obiekt rubinowy w/app/models /. Nie ma powodu, dla którego wszyscy musieliby dziedziczyć po ActiveRecord :: Base

+0

Zrobiłem plik calculator.rb w aplikacji/modelach, który nie dziedziczy po ActiveRecord. Jednak po przeniesieniu kodu do tego pliku nie mogę uzyskać do niego dostępu z widoku. Zakładam, że to dlatego, że zrobiłem to wszystko za pomocą zmiennych lokalnych. Jaki jest najlepszy sposób, aby to naprawić? Próbowałem zmienić je na zmienne globalne, ale to nie pomaga. – Ryan

+0

Umieszczenie metod w modelach, zamiast w klasie w lib /, lepiej wiąże logikę z podstawowymi danymi. Poza tym ma wyraźną zaletę, że nie cierpi na ten problem związany ze zmiennymi instancji, ponieważ można wywoływać metody na instancjach modeli, które już obsługuje w kontrolerze i widokach. Kodowanie do biblioteki/ma sens, jeśli jest używane przez wiele klas w bazie kodu, takich jak moduł Mixin, lub jest czymś, co przekształca się w projekt/plugin wielokrotnego użytku. Jeśli logika jest częścią kodu, zachowaj ją za pomocą głównego kodu. –

5

Istnieje kilka sposobów podejścia, ale logika z pewnością nie należy do tego widoku. Masz różne modele powiązane ze sobą w przejrzystej hierarchii, a górną częścią hierarchii jest model Domu, jeśli poprawnie odczytuję Twój opis. W takim przypadku dodałbym odpowiednią metodę zestawu metod do modelu House'a, który może składać się z wywołań metod obliczeniowych w modelach pomieszczeń powiązanych z daną instancją House i na linii asocjacji. W ten sposób odpowiednie obliczenia mogą być wykonywane na każdym poziomie i poprzez komponowanie jednej lub więcej metod na poziomie modelu House, możesz mieć czysty, wyrazisty i łatwy do utrzymania sposób radzenia sobie z obliczeniami.

Jedną z rzeczy do zrobienia, byłoby upewnienie się, że wszelkie obliczenia, które mogą być wykonywane przez DB. Na przykład, jeśli istnieje kalkulacja, którą model Pokoju może zrobić, po prostu zapytując o własne dane, to wszelkimi środkami popchnij to obciążenie obliczeniowe do DB, używając zdolności ActiveRecord do wywołania logiki obliczeń o niższym poziomie. Aby uzyskać szczegółowe informacje, sprawdź numer API docs.

Chciałbym bardzo uważnie przyjrzeć się logice, którą chcesz i zobaczyć, jak można ją wepchnąć do modelu, ponieważ prawdopodobnie tam, gdzie ona należy, w pobliżu rzeczywistych danych obliczeń oraz w strukturach klas, które reprezentują te dane konkretnie; Nie utworzyłbym modelu tylko po to, by obsłużyć logikę obliczeń, chyba że naprawdę z jakiegoś powodu trzeba przechowywać wytrwale kalkulacje.

1

OK, teraz widzę kod wysłany. Widzę, że calculator_controller faktycznie nie ma w nim żadnych obliczeń, czy są one w widokach ?. Wypróbuj to podejście:

  1. Napisz test, który ustawia obiekt, który zwróci wyniki, które musisz zwrócić użytkownikowi strony internetowej, biorąc pod uwagę dom, pokoje lub cokolwiek innego, czego potrzebuje.
  2. Zbuduj model (w modelach), aby przejść test.
  3. Zmodyfikuj powyższy kod kontrolera, aby użyć nowego modelu kalkulatora.
  4. Zmodyfikuj testy kontrolera, aby je również przekazać. Testy te, oczywiście, nie muszą testować żadnej logiki biznesowej.

Moja przed respose:

Jeśli logika biznesowa jest dość prosty i wykorzystywane jedynie za tej aplikacji internetowej, można umieścić go w folderze app/modeli.

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

Następnie w kontroler, należy utworzyć instancję modelu

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

Następnie w szablonach można do niego dostęp

<%=h @mcc.calculate_coolness %> 

Zauważ, że @other_things jest instance__variable od MyCoolClass i ogólnie niedostępne dla szablonów bez zdefiniowanej metody dostępu

+0

Lubię budować takie modele, gdy logika zaczyna zagracać model AR. –

Powiązane problemy