11

Ho riscontrato un problema con il seguente problema in Rails e ASP.Net MVC. Spesso ci sono più widget di funzionalità in una pagina, tuttavia si suppone che un'azione di controller esegua il rendering della pagina. Lasciatemi illustrare:Qual è la soluzione elegante per le viste non correlate nei framework Web MVC?

Diciamo che ho un normale sito di e-commerce, e il menu è fatto di categorie, mentre la pagina è per visualizzare un gruppo di prodotti.

Per i prodotti, diciamo che hanno un'azione su un controller che sembra qualcosa di simile:

def product_list 
    @products = Products.find_by_category(:name => 'lawnmowers') 
end 

E ho un layout con qualcosa come

<div id="menu"><%= render :partial => 'menu' %></div> 
<div id="content"><%= yield %></div> 

I prodotti hanno una vista. ..

<%= render :partial => 'product', :collection => @products %> 

(si noti che ho ommited la vista del prodotto come irre levant)

e il menu ha un parziale di ...

<% Category.each {|c| %> 
    <%= render :partial => 'menu_node', :locals => { :category => c } %> 
<% } %> 

La linea che ho un problema con è il "Category.each.do" nella vista. Sto recuperando i dati nella vista, invece di usare le variabili che sono state impostate e rilegate nel controller. E potrebbe facilmente essere una chiamata di metodo più complessa che produce il menu.

Le soluzioni che ho prese in considerazione sono:

-A vista del modello classe base che sa come ottenere i vari pezzi di dati. Ma potresti finire con uno di questi per ogni "sezione" concettuale del sito.
-a variabile locale che popola nella parte superiore di ciascun metodo (viola DRY) -la stessa cosa, ma in una chiamata before_filter

Nessuno di questi sembrano molto elegante per me. Non posso fare a meno di guardare questo problema e pensare che un presentatore MVP per vista (non lo schermo) sia una soluzione più elegante.

ASP.Net MVC ha un'azione di rendering (diversa dal rendering di rotaie: azione), che risolve questo problema, ma non sono sicuro di cosa penso di tale soluzione.

Pensieri? Suggerimenti per la soluzione?

Nota aggiunta: Le risposte fornite finora sono buoni suggerimenti. E si applicano all'esempio che ho dato, in cui un menu è probabilmente presente in ogni layout ed è chiaramente secondario rispetto ai dati del prodotto.

Tuttavia, cosa succede se non c'è chiaramente un cittadino di seconda classe? I siti di tipo portale hanno generalmente più widget non collegati, in cui ciascuno è importante.

Ad esempio, cosa succede se questa pagina mostrava le tendenze meteorologiche, con i widget relativi a temperatura, umidità e precipitazioni (e ciascuno di essi è un modello e un tipo di visualizzazione diversi).

+0

domanda eccellente. Ho anche lottato con questo, dato che la mia app ha il potenziale per molti "widget". Penso che ogni widget dovrebbe avere il proprio Controller che sa come inviarlo è dati, ma non è sicuro di come sarebbe implementato in ASP.NET MVC. –

+0

Tendo ad usare RenderAction in questi scenari, ma come hai detto, è tutt'altro che perfetto. – DanP

+0

DanP, ti riferisci a rail o asp.net mvc? –

risposta

3

In binari ci piace avere un concetto di controller sottili, modelli spessi. Quindi penso che tu abbia ragione a non voler avere le variabili impostate nel controller.

Inoltre, al fine di consentire un metodo più complesso in seguito, vi consiglio di fare qualcosa di simile:

/app/controllers/application_controller.rb

before_filter :add_menu_nodes 

def add_menu_nodes 
    @menu_nodes = Category.menu_nodes(current_user) 
end 

/app/views/layout/application.html.erb

<%= render :partial=>:menu, :locals=>{:categories=>@menu_nodes} %> 

/app/models/category.rb

def self.menu_nodes(current_user) 
    Category.all.order(:name) 
end 

In questo modo in futuro è possibile aggiornare Category.menu_nodes con una soluzione più complicata, in base all'utente corrente, se necessario.

+0

grazie, questa è una bella recensione. questa è probabilmente la soluzione più pulita che abbia mai visto sul lato delle rotaie. Presume che questi dati siano necessari su ogni layout. E implica un modello di dati di 2a classe (categorie) che potrebbe non essere il caso. ma penso che sia inevitabile in mvc che tu abbia quel problema. –

1

Perdonami se macellaio Ruby (o fraintendere la tua domanda), ma ciò che è sbagliato con

class section_helper 
    def menu(section) 
     // ... 
     menuBuiltAbove 
    end 
end 

nella vista

<%= section_helper.menu('section') %> 

?

+0

che non è un cattivo suggerimento, ma presuppone che il menu sia un 2o cittadino di classe ai prodotti. Nel caso di un menu, sarei d'accordo. Ma ci sono scenari in cui non è così. Questo è fondamentale per il motivo per cui ho visto mvc come ottimo per siti semplici, in cui ogni pagina ha uno scopo preciso, ma per i siti di tipo portale, penso che il modello stia combattendo. –

+0

@Tim Hoolihan Penso di vedere qual è il tuo problema. Per i portali ho appena usato jquery per effettuare chiamate ajax ai controller e quindi aggiornato il lato client del widget. Forse quell'idea aiuta? –

+0

questa è una soluzione pratica che penso sia soddisfacente, ma penso che sto cercando più di una soluzione di modello. e su siti con prestazioni elevate stiamo aggiungendo richieste http. –