Pregunta

Tengo una aplicación Ruby / Rails que tiene dos o tres secciones principales. Cuando un usuario visita esa sección, deseo mostrar alguna subnavegación. Las tres secciones usan el mismo diseño, por lo que no puedo "codificar". la navegación en el diseño.

Se me ocurren algunos métodos diferentes para hacer esto. Supongo que para ayudar a las personas a votar las pondré como respuestas.

¿Alguna otra idea? ¿O por qué vota?

¿Fue útil?

Solución

Puede hacerlo fácilmente usando parciales, suponiendo que cada sección tenga su propio controlador.

Digamos que tiene tres secciones llamadas Publicaciones , Usuarios y Admin , cada una con su propio controlador: PostsController , UsersController y AdminController .

En cada directorio views correspondiente, declara un _subnav.html.erb parcial:

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

En cada uno de estos parciales de subnav declara las opciones específicas de esa sección, por lo que /users/_subnav.html.erb puede contener:

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

Mientras que /posts/_subnav.html.erb puede contener:

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

Finalmente, una vez que haya hecho esto, solo necesita incluir el subnav parcial en el diseño:

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

Otros consejos

  1. Render parcial . Esto es muy similar al método auxiliar, excepto que el diseño podría tener algunas declaraciones if, o pasarlo a un asistente ...

En cuanto al contenido de sus submenús, puede consultarlo de manera declarativa en cada controlador.

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

Ahora, cada vez que llame a menu_items desde una vista, tendrá la lista correcta para iterar para el controlador específico.

Esto me parece una solución más limpia que poner esta lógica dentro de las plantillas de vista.

Tenga en cuenta que es posible que también desee declarar un elemento de menú predeterminado (¿vacío?) dentro de ApplicationController.

Advertencia: ¡Trucos avanzados por delante!

Renderizarlos todos . Oculte los que no necesita con CSS / Javascript, que se pueden inicializar trivialmente de muchas maneras. (Javascript puede leer la URL utilizada, los parámetros de consulta, algo en una cookie, etc., etc.) Esto tiene la ventaja de potencialmente jugar mucho mejor con su caché (¿por qué almacenar en caché tres vistas y luego tener que expirarlas todas simultáneamente cuando puede almacenar en caché una? ?), y se puede utilizar para presentar una mejor experiencia de usuario.

Por ejemplo , supongamos que tiene una interfaz de barra de pestañas común con navegación secundaria. Si representa el contenido de las tres pestañas (es decir, está escrito en el HTML) y oculta dos de ellas, cambiar entre dos pestañas es un Javascript trivial y ni siquiera llega a su servidor . ¡Gran victoria! Sin latencia para el usuario. No hay carga de servidor para usted.

¿Quiere otra gran victoria ? Puede usar una variación de esta técnica para hacer trampa en páginas que pueden ser comunes en un 99% entre los usuarios pero que aún contienen el estado del usuario. Por ejemplo, es posible que tenga una página principal de un sitio que sea relativamente común entre todos los usuarios pero que diga "Hola Bob". cuando inician sesión. Coloque la parte no común (" Hiya, Bob ") en una cookie. Haga que esa parte de la página se lea a través de Javascript leyendo la cookie. Almacenamiento en caché de toda la página para todos los usuarios, independientemente del estado de inicio de sesión en el almacenamiento en caché de la página. Esto es literalmente capaz de cortar el 70% de los accesos de toda la pila de Rails en algunos sitios.

¿A quién le importa si Rails puede escalar o no cuando su sitio es realmente Nginx sirviendo activos estáticos con nuevas páginas HTML que ocasionalmente recibe Ruby que se ejecuta cada mil veces más o menos;)

Puede usar algo como el complemento de navegación en http: // rpheath. com / posts / 309-rails-plugin-navigation-helper

No realiza la navegación de subsección fuera de la caja, pero con un pequeño ajuste, probablemente podría configurarlo para hacer algo similar.

Te sugiero que uses parciales. Hay algunas maneras de hacerlo. Cuando creo parciales que son un poco exigentes porque necesitan variables específicas, también creo un método auxiliar para ello.

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

Ahora el parcial tiene una variable local llamada menu_items sobre la cual puede iterar para crear su submenú. Tenga en cuenta que sugiero una matriz anidada en lugar de un hash porque el orden de un hash es impredecible.

Tenga en cuenta que la lógica que decide qué elementos deben mostrarse en el menú también podría estar dentro de render_submenu si eso tiene más sentido para usted.

Yo mismo hice la misma pregunta: Necesito consejo: Estructura de vistas de Rails para submenús? La mejor solución fue probablemente usar parciales.

Hay otra forma posible de hacer esto: diseños anidados

No recuerdo dónde encontré este código, así que pido disculpas al autor original.

cree un archivo llamado nested_layouts.rb en su carpeta lib e incluya el siguiente código:

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

luego, cree sus diversos diseños en la carpeta de diseños (por ejemplo, 'admin.rhtml' y 'application.rhtml').

Ahora en sus controladores agregue esto solo dentro de la clase:

include NestedLayouts

Y finalmente, al final de tus acciones, haz esto:

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

el orden de los diseños en la matriz es importante. El diseño del administrador se representará dentro del diseño de la aplicación donde sea que esté 'yeild'.

este método puede funcionar realmente bien dependiendo del diseño del sitio y de cómo se organizan los diversos elementos. por ejemplo, uno de los diseños incluidos podría contener una serie de divs que contienen el contenido que debe mostrarse para una acción en particular, y el CSS en un diseño superior podría controlar dónde se ubican.

Hay pocos enfoques para este problema.

Es posible que desee utilizar diferentes diseños para cada sección.

Es posible que desee utilizar un parcial incluido por todas las vistas en un directorio dado.

Es posible que desee utilizar content_for que se completa con una vista o una parcial, y se llama en el diseño global, si tiene uno.

Personalmente, creo que debería evitar más abstracción en este caso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top