Дизайн панели Rails: одно действие контроллера на div - PullRequest
12 голосов
/ 26 мая 2009

Я реализую информационную панель как относительный новичок в Rails (скорее, специалист по инфраструктуре). Панель инструментов будет состоять из нескольких страниц, каждая из которых будет содержать несколько диаграмм / таблиц / и т. Д. Для модульности я хочу, чтобы было как можно проще добавлять новые диаграммы или изменять представления данных.

Скажем, на одной странице 5 разных графиков. Я мог бы заставить контроллер выполнить 5 отдельных поисков данных, сохранить все соответствующие данные в переменных экземпляра и отобразить 5 партиалов, каждый из которых касается подмножеств данных. Но кажется более модульным иметь одно действие контроллера «index», рендеринг которого имеет кучу элементов div, и для каждого элемента div существует другое действие контроллера, которое выполняет поиск данных и имеет ассоциированное представление, частично отвечающее за управление представлением этих данных. внутри див.

Так что, если я показываю страницу панели инструментов сайта с двумя графиками, website/index будет использовать website/graph1 и website/graph2 для поиска данных для каждого, а затем _graph1.html.erb и _graph2.html.erb будут использовать контроллер данные для заполнения div "graph1" и "graph2" и т. д.

Это правильный дизайн, и если так, какой самый простой способ сделать это? У меня есть аппроксимация, используя remote_function с :action => "graph1" для заполнения div, но я не на 100% доволен этим. Я подозреваю, что упускаю что-то более простое, что Rails сделает для меня.

Ответы [ 4 ]

10 голосов
/ 26 мая 2009

Версия 1:

Простой метод, который я на самом деле использовал в производстве: iframes.

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

Если вы просто добавите iframe src'd в действие show контроллера, у вас будет очень простое решение, которое не требует прямого взаимодействия между контроллерами.

Pro:

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

Минусы:

  • вы не всегда можете легко сохранить страницу вместе с тем, что есть
  • iframes вырвется из пространства имен javascript главной страницы, поэтому, если они этого требуют, вам может понадобиться дать им их собственный минималистский макет; они также не смогут влиять на окружающую страницу за пределами своего iframe
  • может быть медленнее, в зависимости от времени пинга и т. Д.
  • потенциальная ошибка эффективности n + 1, если у вас много таких модулей на странице

Версия 2:

Сделайте то же самое, используя вызовы JS для замены div на частичное, как:

<div id="placeholder">
<%= update_page {|page| page['placeholder'].replace with some partial call here } %>

То же, что и выше, за исключением:

Pro:

  • не блокирует его в iframe, поэтому разделяет контекст JS и т. Д.
  • позволяет лучше обрабатывать случаи отказа

Con:

  • требует JS и местозаполнителя div; немного сложнее

Версия 3:

Назовите целую кучу частичек. Это становится сложным, если вы говорите о таких вещах, как информационные панели, где отдельные модули обладают значительным количеством логики настройки.

Существуют различные способы обойти это, превращая эти вещи в «миксины» или тому подобное, но IMO, они немного глупы.

ETA: способ сделать это через mixins состоит в том, чтобы создать то, что по сути является библиотечным файлом, который реализует функции настройки контроллеров вашего модуля, включать его везде, где используется то, что вызывает их, и вызывать их.

Однако, у этого есть недостатки:

  • Вы должны знать, какие действия контроллера верхнего уровня приведут к страницам, которые содержат эти модули (что может быть непросто, если это действительно сложные вещи, которые могут появляться повсюду, например, в зависимости от предпочтений пользователя)
  • на самом деле он не действует как полноценный контроллер
  • это все еще смешивает много логики, когда ваша вещь должна знать о том, что она держит
  • Вы не можете легко разделить его на собственный контроллер, потому что он должен быть в файле библиотечного типа / mixin

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

Я должен был сделать это один раз - прежде всего потому, что рефакторинг причины был даже БОЛЬШЕ боли - и я обещаю, что вы не хотите идти туда, если вам не нужно.

Резюме

Лучший метод IMHO - первый, если у вас есть достаточно сложные вещи, которые требуют значительных настроек - простой iframe, который отображает модуль, передавая параметр, чтобы сказать ему использовать ультраминималистический макет (просто заголовки CSS + JS), потому что это не отображается как собственная страница.

Это позволяет вам сохранять вещи полностью независимыми, функционировать более или менее так, как если бы они были совершенно обычными собственными контроллерами (кроме настроек макета), сохранять нормальные маршруты и т. Д.

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

7 голосов
/ 13 ноября 2009

почему бы вам не попробовать Apotomo, это виджеты с отслеживанием состояния для Rails:

Учебное пособие по созданию простой панели инструментов

1 голос
/ 26 мая 2009

Вы можете достичь этого, используя

render_output = render: action => "graph2"

Но лично я, вероятно, поместил бы код в общий помощник или написал бы свою собственную "lib" в каталоге lib, чтобы повторно использовать код с общим шаблоном. Помните, что если вы не измените свой файл route.rb, любой публичный метод будет доступен для

/ контроллер / действие /: ID

Также не забудьте отключить макет для функции: layout => nil (или указать в верхней части макета контроллера "graph",: кроме => ["graph2"]

Приветствия

Christian

0 голосов
/ 26 мая 2009

Мне не известны какие-либо специальные приемы Rails для достижения этого без использования AJAX, как вы обрисовали.

Самый простой способ получить искомую модульность - это поместить те части кода контроллера в отдельные методы (например, set_up_graph1_data, set_up_graph2_data и т. Д.), Которые вы просто вызываете из действия index для настройки переменные для представления.

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

Как примечание, в начале Rails делал раньше имел функцию под названием «компоненты», которая позволяла бы вам делать именно то, что вы просите здесь, без необходимости использовать AJAX. С вашей точки зрения, вы можете просто визуализировать другое действие контроллера, встроенное. Однако эта функция была удалена по соображениям производительности и философии дизайна.

...