Pergunta

Eu tenho um aplicativo Ruby / Rails que tem dois ou três principais "seções". Quando um usuário visita essa seção, quero mostrar algumas sub-navegação. Todas as três seções usam o mesmo layout, então eu não posso "codificar" a navegação no layout.

Não consigo pensar em alguns métodos diferentes de fazer isso. Eu acho que, a fim de ajudar as pessoas a votar Vou colocá-los como respostas.

Quaisquer outras ideias? Ou o que você votar?

Foi útil?

Solução

Você pode facilmente fazer isso usando parciais, assumindo cada seção tem seu próprio controlador.

Digamos que você tenha três seções chamado mensagens , Usuários e admin , cada um com o seu próprio controlador:. PostsController, UsersController e AdminController

Em cada diretório views correspondente, você declarar um _subnav.html.erb parcial:

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

Em cada um desses parciais subnav você declarar a opções específicas para essa seção, então /users/_subnav.html.erb pode conter:

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

Enquanto /posts/_subnav.html.erb pode conter:

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

Finalmente, uma vez que você fez isso, você só precisa incluir o subnav parcial no layout:

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

Outras dicas

  1. Parcial tornar . Isto é muito semelhante ao método auxiliar exceto, talvez, o layout teria algum se as declarações, ou passar que fora a um ajudante ...

Quanto ao conteúdo do seu submenus, você pode ir para lá de uma forma declarativa em 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

Agora, sempre que você chama menu_items a partir de um ponto de vista, você terá a lista da direita para iterar para o controlador específico.

Isso me parece uma solução mais limpa do que colocar essa lógica dentro de modelos de visão.

Note que você também pode querer declarar um default (esvaziar?) Menu_items dentro ApplicationController também.

Aviso: Truques Avançados em frente

Render-los todos . Esconder os que você não precisa usar o CSS / Javascript, que pode ser trivialmente inicializado em qualquer número de maneiras. (Javascript pode ler o URL utilizado, os parâmetros de consulta, algo em um cookie, etc etc.) Isto tem a vantagem de potencialmente jogando muito melhor com o seu cache (porquê de cache três pontos de vista e, em seguida, tem a expirar-los todos ao mesmo tempo quando você pode armazenar em cache um ?), e pode ser usado para apresentar uma experiência de usuário melhor.

Por exemplo , vamos fingir que você tem uma interface de barra de abas comum com sub navegação. Se você processar o conteúdo de todas as três guias (ou seja, a sua escrita no HTML) e se esconder dois deles, a alternância entre duas guias é trivial Javascript e não chegou a atingir o seu servidor . Grande vitória! Nenhuma latência para o usuário. Sem carga do servidor para você.

Quer outra grande vitória ? Você pode usar uma variação dessa técnica para enganar sobre páginas que podem, mas 99% comum entre os usuários, mas ainda contêm estado do usuário. Por exemplo, você pode ter uma página de um site, que é relativamente comum para todos os usuários, mas dizer "Oi Bob" quando está logado. Coloque a parte não-comum ( "Oi, Bob") em um cookie. Tem que parte da página ser lido em via Javascript leitura do cookie. Cache a página inteira para todos os usuários, independentemente de status de login na página de cache. Esta é literalmente capaz de cortar 70% dos acessos fora dos trilhos inteiras empilhar em alguns sites.

Quem se importa se Rails pode escalar ou não quando o seu site é realmente Nginx servindo ativos estáticos com novas páginas HTML, ocasionalmente, ficando entregues por alguns Rubi correndo em cada acesso milésima ou assim;)

Você pode usar algo como o plug-in de navegação em http: // rpheath. com.br / posts / 309-rails-plugin-navegação-helper

Ele não faz a navegação sub-seção de fora da caixa, mas com um pouco de ajustes você provavelmente poderia configurá-lo para fazer algo semelhante.

Eu sugiro que você use parciais. Existem algumas maneiras que você pode ir sobre ele. Quando crio parciais que são um exigente bit em que eles precisam de variáveis ??específicas, eu também criar um método auxiliar para ele.

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

Agora, a parcial tem uma variável local chamada menu_items sobre os quais você pode iterar para criar o seu submenu. Note que eu sugiro uma matriz aninhada em vez de um hash, porque a ordem de um hash é imprevisível.

Note que a lógica de decidir quais itens devem ser exibidos no menu também poderia ser render_submenu dentro se isso faz mais sentido para você.

Eu perguntei praticamente a mesma pergunta a mim mesmo: : Estrutura de pontos de vista trilhos para submenus? a melhor solução foi, provavelmente, a parciais de uso.

Há uma outra maneira possível de fazer isso: aninhadas Layouts

Não me lembro onde eu encontrei este código para desculpas ao autor original.

criar um arquivo chamado nested_layouts.rb na sua pasta lib e incluir o seguinte 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

então, criar seus layouts diferentes na pasta layouts, (por exemplo, 'admin.rhtml' e 'application.rhtml').

Agora, em seus controladores adicione apenas dentro da classe:

include NestedLayouts

E, finalmente, no final de suas ações fazer isso:

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

a ordem dos layouts na matriz é importante. O layout de administração será processado dentro do layout da aplicação onde quer que o 'de rendimento que' é.

este método pode funcionar muito bem, dependendo do design do site e como os vários elementos são organizados. por exemplo, um dos layouts incluídos poderia apenas conter uma série de divs que contêm o conteúdo que precisa ser mostrado para uma determinada ação, eo CSS em um layout mais elevado poderia controlar onde eles estão posicionados.

Existem algumas abordagens para este problema.

Você pode querer usar diferentes layouts para cada seção.

Você pode querer usar um parcial incluído por todos os pontos de vista em um determinado diretório.

Você pode querer usar content_for que é preenchido por uma visão ou uma parcial, e chamou no layout global, se você tiver um.

Pessoalmente, eu acredito que você deve evitar mais abstração neste caso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top