Как реализовать специфичную для секции навигацию в Ruby on Rails? - PullRequest
12 голосов
/ 30 сентября 2008

У меня есть приложение Ruby / Rails, которое имеет два или три основных "раздела". Когда пользователь посещает этот раздел, я хочу отобразить некоторую суб-навигацию. Все три раздела используют один и тот же макет, поэтому я не могу «жестко программировать» навигацию в макете.

Я могу придумать несколько разных способов сделать это. Я думаю, чтобы помочь людям проголосовать, я поставлю их как ответы.

Есть еще идеи? Или за что вы голосуете?

Ответы [ 9 ]

9 голосов
/ 01 октября 2008

Вы можете легко сделать это, используя партиалы, предполагая, что каждый раздел имеет свой собственный контроллер.

Допустим, у вас есть три раздела, которые называются Сообщения , Пользователи и Администратор , каждый со своим собственным контроллером: PostsController, UsersController и AdminController.

В каждом соответствующем каталоге views вы объявляете _subnav.html.erb частичное:

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

В каждом из этих поднавных партиалов вы объявляете параметры, специфичные для этого раздела, поэтому /users/_subnav.html.erb может содержать:

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

Хотя /posts/_subnav.html.erb может содержать:

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

Наконец, как только вы это сделаете, вам просто нужно включить частичку subnav в макет:

<div id="header">...</div>    
<%= render :partial => "subnav" %>
<div id="content"><%= yield %></div>
<div id="footer">...</div>
7 голосов
/ 30 сентября 2008

Что касается содержимого ваших подменю, вы можете использовать его декларативно в каждом контроллере.

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

Теперь, когда вы вызываете menu_items из представления, у вас будет правильный список для итерации для конкретного контроллера.

Это кажется мне более чистым решением, чем использование этой логики в шаблонах представления.

Обратите внимание, что вы также можете объявить по умолчанию (пусто?) Menu_items внутри ApplicationController.

7 голосов
/ 30 сентября 2008
  1. Частичная визуализация . Это очень похоже на вспомогательный метод, за исключением того, что, возможно, макет будет содержать некоторые операторы if или передавать его помощнику ...
3 голосов
/ 30 сентября 2008

Внимание: впереди продвинутые трюки!

Отобразить их все . Скройте те, которые вам не нужны, с помощью CSS / Javascript, который можно тривиально инициализировать любым количеством способов. (Javascript может читать используемый URL-адрес, параметры запроса, что-то в cookie-файле и т. Д. И т. Д.) Это имеет преимущество в том, что потенциально может играть намного лучше с вашим кешем (зачем кешировать три представления, а затем нужно одновременно завершать их все, когда вы можете кэшировать одно ?), и может быть использован для представления лучшего пользовательского опыта.

Например, , давайте представим, что у вас есть общий интерфейс панели вкладок с суб-навигацией. Если вы визуализируете содержимое всех трех вкладок (т.е. оно написано в HTML) и скрываете две из них, переключение между двумя вкладками является тривиальным Javascript, и даже не попадает на ваш сервер . Большая победа! Нет задержки для пользователя. Нет загрузки сервера для вас.

Хотите очередной большой выигрыш ? Вы можете использовать вариацию этого метода, чтобы обманывать страницы, которые могут, но 99%, распространены среди пользователей, но все еще содержат пользовательское состояние. Например, у вас может быть титульная страница сайта, которая является относительно обычной для всех пользователей, но при входе в систему вы можете сказать «Hiya Bob». Поместите необычную часть («Hiya, Bob») в файл cookie. Пусть эта часть страницы будет прочитана с помощью Javascript, читающего куки. Кэширование всей страницы для всех пользователей независимо от состояния входа в систему при кэшировании страницы. Это буквально способно отрезать 70% доступа из всего стека Rails на некоторых сайтах.

Кому интересно, может ли Rails масштабироваться или нет, если ваш сайт действительно Nginx обслуживает статические ресурсы с новыми HTML-страницами, иногда доставляемыми каким-то Ruby, работающим на каждом тысячном доступе или около того;)

1 голос
/ 01 октября 2008

Существует еще один возможный способ сделать это: Nested Layouts

Я не помню, где я нашел этот код, поэтому извиняюсь перед автором.

создайте файл с именем nested_layouts.rb в вашей папке lib и включите следующий код:

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

затем создайте различные макеты в папке раскладок (например, «admin.rhtml» и «application.rhtml»).

Теперь в ваших контроллерах добавьте это только внутри класса:

include NestedLayouts

И, наконец, в конце своих действий сделайте следующее:

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

важен порядок расположения в массиве. Макет администратора будет отображаться внутри макета приложения, где бы ни было слово "yeild".

этот метод может работать очень хорошо в зависимости от дизайна сайта и от того, как организованы различные элементы. например, один из включенных макетов может просто содержать серию div, которые содержат контент, который должен быть показан для определенного действия, и CSS на более высоком макете может контролировать, где они расположены.

1 голос
/ 01 октября 2008

Я сам задавал почти тот же вопрос: Нужен совет: структура представлений Rails для подменю? Лучшим решением, вероятно, было использование партиалов.

1 голос
/ 30 сентября 2008

Я предлагаю вам использовать частичные. Есть несколько способов сделать это. Когда я создаю партиалы, которые немного требовательны к тому, что им нужны определенные переменные, я также создаю для них вспомогательный метод.

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

Теперь у части есть локальная переменная с именем menu_items, по которой вы можете выполнить итерацию, чтобы создать ваше подменю. Обратите внимание, что я предлагаю использовать вложенный массив вместо хэша, поскольку порядок хэша непредсказуем.

Обратите внимание, что логика, решающая, какие элементы должны отображаться в меню, также может быть внутри render_submenu, если это имеет для вас больше смысла.

1 голос
/ 30 сентября 2008

Вы можете использовать что-то вроде навигационного плагина на http://rpheath.com/posts/309-rails-plugin-navigation-helper

Он не выполняет навигацию по подразделам из коробки, но с небольшими изменениями вы, вероятно, можете настроить его на выполнение чего-то подобного.

0 голосов
/ 26 декабря 2008

Есть несколько подходов к этой проблеме.

Возможно, вы захотите использовать разные макеты для каждого раздела.

Возможно, вы захотите использовать частичное, включенное во все представления в данном каталоге.

Возможно, вы захотите использовать content_for, который заполнен либо видом, либо частичным, и вызывается в глобальном макете, если он у вас есть.

Лично я считаю, что в этом случае вам следует избегать большей абстракции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...