Какое изящное решение для несвязанных представлений в веб-фреймворках MVC?
У меня возникла проблема со следующей проблемой в Rails и ASP.Net MVC. Часто на странице есть несколько виджетов функциональности, но одно действие контроллера должно отображать страницу. Позвольте мне проиллюстрировать:
Скажем, у меня есть обычный сайт электронной коммерции, а меню сделано из категорий, а на странице отображается группа продуктов.
Для продуктов, скажем, у меня есть действие над контроллером, которое выглядит примерно так:
def product_list
@products = Products.find_by_category(:name => 'lawnmowers')
end
И у меня есть макет с чем-то вроде
<div id="menu"><%= render :partial => 'menu' %></div>
<div id="content"><%= yield %></div>
Продукты имеют вид...
<%= render :partial => 'product', :collection => @products %>
(обратите внимание, что я не видел представления продукта как несущественного)
И в меню есть частичный...
<% Category.each {|c| %>
<%= render :partial => 'menu_node', :locals => { :category => c } %>
<% } %>
У меня есть проблема с "Category.each.do" в представлении. Я получаю данные в представлении, в отличие от использования переменных, которые были установлены и связаны в контроллере. И это может быть легко более сложный вызов метода, создающий меню.
Решения, которые я рассмотрел, следующие:
- Просмотр базового класса модели, который знает, как получить различные части данных. Но вы могли бы получить один из них для каждого концептуального "раздела" сайта.
- локальная переменная, которая заполняется в верхней части каждого метода (нарушает DRY)
- то же самое, но в вызове before_filter
Ни один из них не кажется мне очень изящным. Я не могу не смотреть на эту проблему и думать, что презентатор MVP для представления (а не экран) является более элегантным решением.
ASP.Net MVC оказывает действие (отличное от rails render: action), которое делает это, но я не уверен, что я думаю об этом решении.
Мысли? Рекомендации по решению?
Добавлено Примечание:
Ответы, представленные до сих пор, являются хорошими предложениями. И они применимы к примеру, который я дал, где меню, вероятно, присутствует в каждом макете, и явно является вторичным по отношению к данным продукта.
Однако, что, если явно нет гражданина второго сорта? Сайты типа портала обычно имеют несколько несвязанных виджетов, в которых каждый из них важен.
Например, Что делать, если на этой странице отображались тенденции погоды, с виджетами для температуры, влажности и осадков (и каждая из них отличается от модели и вида вида).
Ответы
Ответ 1
В рельсах нам нравится иметь концепцию тонких контроллеров, толстых моделей. Поэтому я думаю, что вы правы, чтобы не хотеть иметь переменные, установленные в контроллере.
Кроме того, чтобы позже включить более сложный метод, я рекомендую сделать что-то вроде:
/app/controllers/application_controller.rb
before_filter :add_menu_nodes
def add_menu_nodes
@menu_nodes = Category.menu_nodes(current_user)
end
/app/views/layouts/application.html.erb
<%= render :partial=>:menu, :locals=>{:categories=>@menu_nodes} %>
/app/models/category.rb
def self.menu_nodes(current_user)
Category.all.order(:name)
end
Таким образом, в будущем вы можете обновить Category.menu_nodes с более сложным решением, основанным на текущем пользователе, если вам нужно.
Ответ 2
Простите меня, если я мясник Ruby (или неправильно понял ваш вопрос), но что не так с
class section_helper
def menu( section )
// ...
menuBuiltAbove
end
end
в представлении
<%= section_helper.menu( 'section' ) %>
?