Ruby on Rails
Comments 44
+4
За kaminari спасибо.

Путь к красивому коду протекает через бурелом говнокода ))))
0
kaminari судя по тестом сильно медленнее, чем will_paginate, хотя может исправили уже.
0
Статья направляет человека на верный путь, однако реальность сурова и некоторые вещи просто не укладываются в концепцию REST, к которой строго принуждают эти ваши inherited_resources. Хотя к этому надо стремиться.
0
Яркий пример: главная страница сайта (где есть новости, блоги, последние комментарии к чему-либо). В общем где контроллер обращается к более чем одной модели.

P.S. Это, конечно, резко с моей стороны утверждать, что что-то не укладывается в REST — при желании можно уложить почти все, тут вопрос в том, стоит ли овчинка выделки.
0
Проще всего это организовать через before_filter. Вот пример контроллера главной страницы, который как раз показывает новости и последнии комментарии:

class PostsFeedsController < InheritedResources::Base
 respond_to :html, :rss, :only => :index
 actions :index

 before_filter lambda{ @latest_comments = Comment.by_domain(Domain.current_domain).latest(10) }
 before_filter lambda{ @latest_posts = Post.by_domain(Domain.current_domain).latest(10) }
 caches_page :index, :unless => lambda {|c| c.user_signed_in?}

 include Platform::Controllers::Paginate
 include Platform::Controllers::Domain
 include Platform::Controllers::EagerLoading
end


* This source code was highlighted with Source Code Highlighter.
+1
Фильтры кажутся, как бы это сказать, wrong place for that.
В RoR есть какая-нибудь возможность вызвать другой Action из View и поместить его результат в месте вызова?
0
Что-то мне подсказывает, что Partials — это не то. Мы же должны передать в Partial данные из «основного» шаблона, разве не так?
0
Посмотрел, да, Cells именно для таких сценариев. Странно только, что он нестандартный.

Кстати, они их описывают как mini-контроллеры. А нет ли возможности вызывать один и тот же Action одного и того же контроллера:
— как из браузера напрямую (и тогда будет сформирована страница этого ресурса), и
— из другого View (и тогда результат будет в виде Partial вставлен в «основную» страницу)?
0
Потому что контроллер — это штука формирующая ответ на запрос. Одно действие — один ответ. Можно конечно выдать скелет страницы в ответе, а блоки с новостями, блогами и т.п. подгружать динамически — по запросу на блок — это тоже вариант. Эдакая система виджетов.
0
«Потому что контроллер — это штука формирующая ответ на запрос. Одно действие — один ответ.»

Я бы так не сказал. Front Controller (независимо от того, как реализован на конкретной платформе) — да, выдает один ответ. А каждый отдельный контроллер вовсе не обязан выдавать только свой результат сразу в браузер пользователя, их можно комбинировать. В ASP.NET MVC это RenderAction, уверен, в RoR это делается похожим образом. В выходящий поток (в браузер пользователя) выдается уже полная страница, независимо от того, сколько контроллеров над ней «поработало».
-1
Тут можно уйти в теорию (что не хотелось бы). Но по-моему концепция формирования одного view несколькими контроллерами — это уже не MVC. Хотя это удобно — спору нет. Кажется cells в Rails делает нечто подобное.
0
Не, в теорию уходить не нужно. Концепция формирования кусочков View несколькими контроллерами — вполне укладывается в MVC, сохраняется и Separation of Concerns, и паттерн Front Controller, и все прочее. ASP.NET MVC именно так и устроен. И да, это чертовски удобно :)
0
Cells — да, миниатюрные контроллеры со своими views, вызовы которых можно встроить в любой view.

Но мне кажется, тут больше подходит использование составной модели.
0
Refinery CMS очень их использует, это так сказать собранные в один «модуль» MVC кусочки, которые можно вызывать из «центральной» системы :)
refinerycms.com/engines
0
Имхо главное правильно разбить логику на сущности. Да, иногда при этом сущности плодятся, но зато потом не возникает проблем с расширением.
+1
Все верно. тогда эти советы работают максимально эффективно
0
А при чем тут REST? Если приложение поддерживает этот архитектурный стиль, вовсе не значит, что не может быть эдаких «обобщенных ресурсов» вроде «главной страницы» или какой-нибудь с виджетами и Pagelet-ами.
0
Спасибо, хорошая статья. Вот еще нашел интересную штуку в вики по Devise: github.com/kristianmandrup/cream
Объединяет аутенфикацию юзеров с помощью Devise, распределению ролей и групп через Roles и авторизации через CanCan.

Если буду создавать новый проект, то этот гем будет установлен в первую очередь.
0
Пробовали его использовать, но мне он показался сырым и глючным
+1
А есть ли практический смысл уменьшать код контроллеров? Его там и так не много, это модели разрастаются до сотен строк, а контроллеры обычно тонкие.
+2
Смысл есть когда в 5 контроллерах 90% кода — это нагенеренный CRUD, а остальные 10% — кастомные before filters.
+2
Ну эстетически будет красивее, да. Но практически толку от этого мало, читаемость кода не повысит (что там читать в сгенерированом контроллере), скорость разработки это не увеличит, а вот если к проекту подключится новый человек не знакомый с методикой, то ему придется потратить какое-то время на то что бы понять принципы.
-1
После этой статьи времени новичку потребуется минимум.
Если кто-то добавил в сгенерированный контроллер какие-то правки (скоуп, дополнительная проверка или инициализация), то читать придется все в полном объеме и вникать. А таким способом — все отклонения от стандартного поведения видны сразу.
+1
Забыли упомянуть Rabl для генерации json, xml ответов. Для создания API приложения, ему нет равных, очень удобен.
+1
inherited_resources очень спорный, ни одно приложение (кроме блога за пять минут) не укладывается в стандартный crud-контроллер. А inherited_resources с нестандартным контроллером — это изучение дополнительного API, сложность чтения кода и лишний, достаточно тяжеловесный гем наполненный метапрограмминговой магией. Зачем? Вам трудно написать def edit; ...; end;?
-1
Основные CRUD действия, как правило, остаются. Конечно приходится добавлять и другие, но inherited_resources здесь совсем не мешает, зато дисциплинирует.
Насчет сложности чтения, как с HAML — вопрос привычки.
def edit; ...; end; — написать не сложно, но зачем писать одно и тоже многократно?
+1
Нет, я говорю о том, что дело никогда не ограничивается чистыми методами crud. Т.е. и index и update и пр. методы всегда расширяются: добавляются фильтры, работа с конечными автоматами, да хоть та же пагинация. По большому счету вы всю логику контроллере выносите в before_filter's и приватные методы которые дергаются IR. Это дезориентирует и в конечном счете превращает код в лапшу. Не говоря уже о том, что приходится писать больше кода.
0
Никто не мешает общие части вынести в плагины, гемы или модули.
+1
Общие то понятно, но что делать с индивидуальными. Мы просто все переносим с больной головы на здоровую. Вместо методов мы все пишем в бифор-фильтры, super do и всячески экстендим collection; Зачем тогда вообще брать руби и рельсы?
+1
Согласен, inherited_resources — это вещь в стиле «как сделать простые вещи сложными». Если в проекте много однотипных простеньких контроллеров, то в разы лучше будет создать обычный базовый класс контроллера с минимумом магии и метапрограммирования, который идеально подойдёт под потребности конкретного проекта.
А использовать inherited_resources для нетривиальных контроллеров == снижать читабельность кода в разы.
+2
… заслуживают отдельной статьи

организуете отдельную статью?
UFO landed and left these words here
-3
Паш, прикольно что статья в топ вышла :)
Твой подход помню, хотя скажу что у меня он не прижился.

Но вот очень понравилось, как ты объединял edit и new views, до сих пор использую.
Only those users with full accounts are able to leave comments. , please.