Как стать автором
Обновить

Комментарии 34

Спасибо за статью. В рунете до сих сложно найти хорошие статьи о Ruby on Rails для новичков. Жду продолжения :)
За то наши западные коллеги изобилуют. За целый день устаешь от английского +)
Спасибо, очень полезно для новичков.
Скомканно. Нет объяснений по какому принципу редактируются роуты.

Например, что мы сделали с последним — я вообще не понял.
Ближе к концу я начал уже торопиться, ибо рабочее время поджимало — поэтому начал суетиться.

Про последнее.
Стандартные роуты (map.resources) прописывают автоматически только один роут без ID (index), а все остальные методы по умолчанию требуют ID (:controller/:action/:id). но часто бывает, что создается метод, который «сам по себе» (в нашем случае это метод random). Для этого метода автоматически прописывается роут вида magazines/random/ID. При этом какой ID не впихни — это никак не повлияет (потому что он просто там никак не используется). Можно, конечно, так и оставить, но это не красиво. Поэтому я привел решение, как такие коллизии решаются. То есть как привести роут к виду :controller/:action (magazines/random). Собственно добавлением опции :collection = { :action => :HTML_method }.
Круто. Собственно, зачем мы это делали и так было ясно, не ясно было — как.

Предлагаю добавить в статью пару предложений про опцию :collection.
Внес небольшую правку.
Более основательно описывать опции и виды роутов я думаю в следующей статье.
тогда если уж говорить про collection, то надо и member упомянуть. Но это думаю уже в следующей статье =)
Именно это я и озвучил вроде)
Я бы не называл моделью базу данных — все таки уровни доступа к данным и уровень бизнес-логики — разные вещи.
Вы устрашающе правы, но это малоактуально =). Думаю вы понимаете о чем я. Тут много каких обобщений которые имеют исключительно фигуральную ценность.
Согласен. Я то все прекрасно понял. Просто те, для кого эта тема новая, могут в итоге ассоциировать эти понятия и в итоге неправильно трактовать паттерн в дальнейшем.

Думаю, раз речь идет об MVC, можно сделать небольшое отступление, где кратко описать роль каждого из компонентов (M, V и C) и что они представляют, а в основном тексте уже использовать просто «Модель».

Ибо для общего понимания важны все детали, даже те, которые, казалось бы, в целом не имеют прямого отношения к делу.
Ну, просвещения ради я там ссылку на MVC дал )
Вообще это тема другой беседы. И я, честно говоря, не стал бы браться за разъяснение паттернов. Для меня это нечто на уровне ощущений. А еще я никогда себя не корю за сложную выборку из контроллера -). МВЦ все же нечто из разряда «идеального» Платона.
Ну да, ссылки вполне достаточно :)
Не, паттерны для меня после участия в масштабных проектах — как раз не на уровне ощущений, а самая что ни на есть практика.
Все конечно зависит от конкретного проекта, но в крупном проекте, который придется поддерживать в длительной перспективе, развивать и переписывать со временем, я бы, как руководитель, навалял бы люлей за сложную выборку в контроллере :)) Впрочем, опять же зависит от того, какой и где MVC использовать.
Хотя, я говорю про ASP.NET MVC, который мы использовали, и он по концепции является абсолютным аналогом MVC в RoR. Так что люлей не избежать :)
Вот же нарвался)
Для полноты картины нужна вторая часть, с map.root, :shallow, вложенными роутерами и :only, :except.
Да-да. Продолжение будет)
возможно ли обойти следующее ограничение и есть ли оно вообще?
/home/:routeName будет /home/чтотоName

хм. если бы как-то поподробнее. Что здесь? )
ну смотри, есть начало роута: но нет конца
те конструкции типа :routetest можно воспринимать как роут :route и строку test или как один роут :routetest
:blabla — это символ, он никак не делится, поэтому конструкция типа :routetest — будет восприниматься только как символ :routetest =)
но можно сделать такой роут (что будет идентично):
map.test '/HOME/:action:test', :controller => 'magazines', :action => 'index', :test=>'test'
если вызвать роут test.path получим /HOME/indextest
какие интересные у вас костыли ;)
спасибо за ответ
какая задача — такие и костыли =)
Есть вариант сделать кетч-алл роут типа такого:
map.connect '*path', :controller => 'redirect', :action => 'index'
и уже потом делать отбор в контроллере того, что надо.
Вот рельсокаст на эту тему:
railscasts.com/episodes/46-catch-all-route
Спасибо за статью.
Знающие люди, подскажите пожалуйста, насколько легально (с идеологической точки зрения) делать так?:

Есть двухуровневое дерево категорий. У модели Category есть атрибут nice_url, который определяется из title'a категории путём выкидывания пробелов и других символов «плохих» для url. Известно, что категорий не много и меняются они нечасто.

В routes.rb я пишу:

Category.find(:all, :conditions => {parent_id => nil}).each do |category|
category.children.each do |subcategory|
map.connect "#{category.nice_url}/#{subcategory.nice_url}", :controller => 'articles', :category_id => subcategory.id
end
map.connect "#{category.nice_url}", :controller => 'articles', :category_id => category.id
end

таким образом я получаю для всего дерева категорий роуты вида:
map.connect «science/biology», :controller => 'articles', :category_id => 31
map.connect «science/math», :controller => 'articles', :category_id => 24
map.connect «science», :controller => 'articles', :category_id => 54
map.connect «programming/php», :controller => 'articles', :category_id => 23
map.connect «programming/cpp», :controller => 'articles', :category_id => 11
map.connect «programming/ruby», :controller => 'articles', :category_id => 26
map.connect «programming», :controller => 'articles', :category_id => 87


Для верности в модели Category добавляю обработчик after_save, который перегружает роуты (вызывается нечасто)
ActionController::Routing::Routes.reload!

Опять же вопрос. Насколько валидно так делать? Как сделать роуты вида «category/subcategory/article», при условии, что статей, в отличии от категорий много, а часто перегружать все роуты — не вариант?

ЗЫ. Про Route globbing [map.connect '*path', :controller => 'articles', :action => 'unrecognized?'] я знаю, и надеюсь, что есть другой способ, без ручного разбора url, а самое главное без последующей ручной, его генерации.

ЗЗЫ. Хотя это коммент-вопрос, возможно кому-то такой подход к динамическим роутам будет интересен/полезен. Во второй версии рельсов это работало без проблем.

А так не пробовали

#routes.rb
map.connect ':parent/:child/:action/:id', :controller => 'articles', :action => 'index', :id => 'nil'

#articles_controller.rb
parent = Category.find_by_title(params['parent'])
child = Category.find_by_title(params['child'], :conditions => ['parent = ?', parent.id])

Как-то так, нет?
Спасибо, но это немного не то… так мне в контроллере нужно найти парента по nice_url, убедиться, что у него есть чайлд, с соответствующим nice_url, а потом получить id чайлда и выбрать нужные данные.

Аналогично при вызове функции url_for или link_to мне нужно иметь информацию о чайлде и паренте (если он есть… это тоже надо проверять).

В описаном мной подходе нужно всего лишь написать url_for(:controller=>'articles', :category_id=>26) и мне неважно на каком уровне вложенности лежит категория с id=26. Ц меня автоматом подхватится роут
map.connect «programming/ruby», :controller => 'articles', :category_id => 26
и вернётся ссылка «programming/ruby»
Очень специфический подход ;)
Попробуйте использовать символы в таком случае
К примеру, вместо
map.connect "#{category.nice_url}/#{subcategory.nice_url}", :controller => 'articles', :category_id => subcategory.id
map.connect "#{category.nice_url}", :controller => 'articles', :category_id => category.id
попробуйте так
map.connect ":parent/:child", :controller => 'articles', :category_id => subcategory.id, :parent => '#{category.nice_url}', :child => '#{subcategory.nice_url}'
map.connect ":parent", :controller => 'articles', :category_id => category.id, :parent => '#{category.nice_url}'

Тогда в котроллере вы сможете пользоваться параметрами GET через params['parent'] и params['child'], которые вернут те самые nice_url
ехх… google to_param и всё будет очень правильно.
Напишите что это Rails, а не весь Руби — Ruby is not Rails ;). Ещё же есть Merb, там другой API у route (например, опциональные параметры можно задать без регулярных выражений:
map('(/:lang)/:article(.:format)').to(:controller => :article, :action => :show).name(:article)
А, например, в Ramaze роутеры строятся динамически на основе имён класса и методов.
Вы про блог? Блога по рельсам нет. А вообще из статьи ясно, что речь о рельсах, а не руби =)
И, кстати, более правильно использовать RESTfull роутеры:
resource :post
создаст сразу роутеры:
GET post/ — просмотр всех постов
PUT post/ — добавление ного
GET post/:id — просмотр конкретного поста
GET post/:id/edit — страница редактирования
POST post/:id — изменение поста
DELETE post/:id — удаление поста
Ну да, про рестфул я еще отдельно написать хочу. Это все же целая идеология ).
Роуты это все же не роутеры =)
Может не в тему, но вот прикольная штучка для работы с субдоменами subdomain-fu
в роутах пишем:
map.connect '*path', :controller => 'users', :action => 'show', :conditions => { :foreign_domain => true }
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.