условный вид / макет - PullRequest
       10

условный вид / макет

2 голосов
/ 26 апреля 2009

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

Пока что моя идея состоит в том, чтобы иметь два контроллера продукта в разных пространствах имен - app/controllers/admin/products_controller.rb и app/controllers/store/products_controller.rb - каждый из которых имеет свои собственные представления и схемы. Но я подозреваю, что это может привести к WET-коду. Или ссылки на другие виды контроллеров (которые imo нарушают модульность и, следовательно, следует избегать).

Итак, актуальный вопрос: есть ли более СУХОЙ (или на самом деле правильный) способ достичь вышеуказанного?

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

EDIT Начиная с 3.1 Rails поддерживает наследование шаблонов.

Ответы [ 4 ]

2 голосов
/ 26 апреля 2009

Если отображение продуктов между разделом администратора и разделом магазина является постоянным, за исключением ссылок администратора («Создать», «Редактировать», «Уничтожить»), то я думаю, что было бы проще всего создать партиал для вашего продукта. Я предполагаю, что у вас есть способ узнать, является ли пользователь администратором или нет (я просто буду использовать admin? Для простоты ниже). Внутри своей части вы делаете что-то вроде этого ...

<div class="product">
    <div class="productheader">
        <%=h product.title %>
    </div>
    <div class="productdescription>
        <%=h product.description %>
    </div>
    <% if admin? %>
    <div class="productadmin">
        <%= link_to "Delete", destroy_product_url %>
        <%= link_to "Edit", edit_product_url %>
    </div>
    <% end %>
</div>

Обязательно назовите этот частичный _product.html.erb (подчеркивание говорит рельсам, что шаблон является частичным). Создайте папку в каталоге app / views вашего приложения с именем shared и сохраните там частичное.

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

Один продукт:

<%= render(:partial => "shared/product", :object => @a_product) %>

Несколько продуктов:

<%= render(:partial => "shared/product", :collection => @products) %>

Макеты можно применить к частям, добавив параметр макета. Частичные макеты должны начинаться с подчеркивания, но должны храниться в каталоге app / views, связанном с контроллером.

<%= render(:partial => "shared/product", :object => @a_product, :layout => "somelayout" %>
1 голос
/ 26 апреля 2009

Подход, который я выбрал, заключается в том, чтобы иметь один контроллер для продуктов и добавлять к нему код для определения роли, которую играет пользователь, и условно устанавливать данные представления на основе этой роли. Это включает как фактические данные модели, так и данные, используемые только представлением, чтобы определить, какие биты интерфейса отображать. Таким образом, само представление содержит небольшой объем кода, который может воздействовать на данные на основе ролей и отображать только те биты, которые имеют отношение к конкретной роли. Кто-то может возразить, что это привносит в представление либо небольшую часть бизнес-логики, либо небольшую часть отображаемой логики в контроллер - и эти аргументы имеют некоторую обоснованность. Тем не менее, я считаю, что на самом деле это скорее баланс между принципами, и я предпочитаю значение DRY чистоте MVC.

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

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

Применив его к моим рельсам 2.2, мне удалось получить следующий ответ на исходный вопрос.

Контроллер подклассов

ProductController был благословлен близнецами:

class Products::AdminController < ProductsController
  layout 'admin'
  before_filter :authenticate
end

и

class Products::StoreController < ProductsController
  layout 'store'
  before_filter :find_cart
end

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

Изменение маршрутов

  map.resources :products, :controller => 'products/admin', :path_prefix => 'admin',
    :name_prefix => 'admin_'
  map.resources :products, :controller => 'products/store', :path_prefix => 'store',
    :only => [:show, :index], :name_prefix => 'store_'

Не простой маршрут, дефо. Но, эй, после этого все просто работает (при условии, что вы исправили пути помощников) с представлениями и частями ProductController.

Изменения общих представлений

Каждый контроллер подкласса имеет свою собственную версию index.html.erb. Все остальное делится в базовом классе.

Говоря о помощниках пути в общих шаблонах. Что раньше было

<% form_for @product ... %>

становится

<% form_for [controller_name, @product] ... %>

и тоньше, как

<%= link_to products_path %>

превращается в

<%= link_to send("#{controller_name}_products_path") %>

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

0 голосов
/ 26 апреля 2009

Вы описываете модель Model-View-Controller, в которой виды моделей и контроллеры могут изменяться ортогонально (или более или менее ортогонально, в зависимости от того, как он реализован).

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

...