Domanda

Ho un'app Ruby / Rails che ha due o tre "sezioni" principali. Quando un utente visita quella sezione, desidero visualizzare un po 'di navigazione secondaria. Tutte e tre le sezioni utilizzano lo stesso layout, quindi non posso " hard code " la navigazione nel layout.

Posso pensare a diversi metodi per farlo. Immagino che per aiutare le persone a votare le metterò come risposte.

Altre idee? O per cosa voti?

È stato utile?

Soluzione

Puoi farlo facilmente usando i parziali, supponendo che ogni sezione abbia il suo controller.

Supponiamo che tu abbia tre sezioni chiamate Post , Utenti e Ammin , ognuna con il proprio controller: PostsController , UsersController e AdminController .

In ciascuna directory viste corrispondente, dichiari un _subnav.html.erb parziale:

/app/views/users/_subnav.html.erb
/app/views/posts/_subnav.html.erb
/app/views/admin/_subnav.html.erb

In ognuno di questi subnav parziali dichiari le opzioni specifiche per quella sezione, quindi /users/_subnav.html.erb potrebbe contenere:

<ul id="subnav">
  <li><%= link_to 'All Users', users_path %></li>
  <li><%= link_to 'New User', new_user_path %></li>
</ul>

Mentre /posts/_subnav.html.erb potrebbe contenere:

<ul id="subnav">
  <li><%= link_to 'All Posts', posts_path %></li>
  <li><%= link_to 'New Post', new_post_path %></li>
</ul>

Infine, una volta terminato, devi solo includere il subnav parziale nel layout:

<div id="header">...</div>    
<%= render :partial => "subnav" %>
<div id="content"><%= yield %></div>
<div id="footer">...</div>

Altri suggerimenti

  1. Rendering parziale . Questo è molto simile al metodo helper, tranne forse che il layout avrebbe alcune istruzioni if ??o lo passerebbe a un helper ...

Per quanto riguarda il contenuto dei sottomenu, puoi esaminarlo in modo dichiarativo in ciascun controller.

class PostsController < ApplicationController
#...
protected
  helper_method :menu_items
  def menu_items
    [
      ['Submenu 1', url_for(me)],
      ['Submenu 2', url_for(you)]
    ]
  end
end

Ora ogni volta che chiami menu_items da una vista, avrai la lista giusta per scorrere l'iter per il controller specifico.

Questo mi sembra una soluzione più pulita rispetto all'inserimento di questa logica nei modelli di visualizzazione.

Nota che potresti voler dichiarare un menu_item predefinito (vuoto?) anche all'interno di ApplicationController.

Avviso: trucchi avanzati in avanti!

Renderli tutti . Nascondi quelli che non ti servono utilizzando CSS / Javascript, che possono essere banalmente inizializzati in qualsiasi numero di modi. (Javascript può leggere l'URL utilizzato, i parametri di query, qualcosa in un cookie, ecc. Ecc.) Questo ha il vantaggio di giocare potenzialmente molto meglio con la cache (perché memorizzare nella cache tre visualizzazioni e quindi scaderle tutte contemporaneamente quando è possibile memorizzarne una nella cache ?) e può essere utilizzato per presentare un'esperienza utente migliore.

Ad esempio , facciamo finta di avere un'interfaccia della barra delle schede comune con navigazione secondaria. Se visualizzi il contenuto di tutte e tre le schede (ovvero è scritto nell'HTML) e ne nascondi due, passare da una scheda all'altra è banale Javascript e non colpisce nemmeno il tuo server . Grande vincita! Nessuna latenza per l'utente. Nessun carico di server per te.

Vuoi un'altra grande vittoria ? Puoi utilizzare una variante di questa tecnica per imbrogliare pagine che potrebbero essere comuni al 99% tra gli utenti ma che contengono comunque lo stato dell'utente. Ad esempio, potresti avere una prima pagina di un sito che è relativamente comune a tutti gli utenti ma che dice "Hiya Bob" quando sono connessi. Inserisci la parte non comune (" Hiya, Bob ") in un cookie. Fai leggere quella parte della pagina tramite Javascript leggendo il cookie. Memorizza nella cache l'intera pagina per tutti gli utenti indipendentemente dallo stato di accesso nella memorizzazione nella cache della pagina. Questo è letteralmente in grado di tagliare il 70% degli accessi dall'intero stack di Rails su alcuni siti.

Chi se ne frega se Rails può scalare o meno quando il tuo sito è davvero Nginx che serve asset statici con nuove pagine HTML occasionalmente consegnati da alcuni Ruby in esecuzione su ogni millesimo accesso o giù di lì;)

Puoi usare qualcosa come il plugin di navigazione su http: // rpheath. com / messaggi / 309-rails-plugin-navigazione-helper

Non esegue la navigazione della sottosezione immediatamente, ma con un po 'di modifica potresti probabilmente configurarla per fare qualcosa di simile.

Ti suggerisco di usare i parziali. Ci sono alcuni modi in cui puoi farlo. Quando creo dei parziali un po 'esigenti in quanto hanno bisogno di variabili specifiche, creo anche un metodo di supporto per questo.

module RenderHelper
  #options: a nested array of menu names and their corresponding url
  def render_submenu(menu_items=[[]])
    render :partial => 'shared/submenu', :locals => {:menu_items => menu_items}
  end
end

Ora il parziale ha una variabile locale denominata menu_items su cui è possibile iterare per creare il sottomenu. Nota che suggerisco un array nidificato anziché un hash perché l'ordine di un hash è imprevedibile.

Nota che la logica che decide quali elementi dovrebbero essere visualizzati nel menu potrebbe anche essere dentro render_submenu se questo ha più senso per te.

Ho fatto praticamente la stessa domanda: Hai bisogno di consigli: Struttura delle viste Rails per i sottomenu? Probabilmente la soluzione migliore era usare i parziali.

Esiste un altro modo possibile per farlo: layout nidificati

Non ricordo dove ho trovato questo codice, quindi mi scuso con l'autore originale.

crea un file chiamato nested_layouts.rb nella tua cartella lib e includi il seguente codice:

module NestedLayouts
  def render(options = nil, &block)
    if options
      if options[:layout].is_a?(Array)
        layouts = options.delete(:layout)
        options[:layout] = layouts.pop
        inner_layout = layouts.shift
        options[:text] = layouts.inject(render_to_string(options.merge({:layout=>inner_layout}))) do |output,layout|
          render_to_string(options.merge({:text => output, :layout => layout}))
        end
      end
    end
    super
  end
end

quindi, crea i tuoi vari layout nella cartella layout (ad esempio "admin.rhtml" e "application.rhtml").

Ora nei tuoi controller aggiungilo appena dentro la classe:

include NestedLayouts

E infine alla fine delle tue azioni fai questo:

def show
  ...
  render :layout => ['admin','application']
end

l'ordine dei layout nell'array è importante. Il layout dell'amministratore verrà reso all'interno del layout dell'applicazione ovunque si trovi "yeild".

questo metodo può funzionare davvero bene a seconda del design del sito e di come sono organizzati i vari elementi. ad esempio, uno dei layout inclusi potrebbe contenere solo una serie di div che contengono il contenuto che deve essere mostrato per una determinata azione e il CSS su un layout più alto potrebbe controllare dove sono posizionati.

Esistono pochi approcci a questo problema.

Potresti voler usare layout diversi per ogni sezione.

Potresti voler usare un parziale incluso da tutte le viste in una data directory.

Potresti voler usare content_for che è riempito da una vista o da un parziale e chiamato nel layout globale, se ne hai uno.

Personalmente credo che dovresti evitare più astrazioni in questo caso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top