Routing в Rails

в 14:18, , рубрики: rails, routing, ruby, ruby on rails, метки: , ,

Большая и интересная тема маршрутизации в Rails подвигла меня на написание этой статьи. В статье я постараюсь человеческим языком описать основы маршрутизации и ответить на несколько вопросов, которые чаще всего возникают у людей, столкнувшихся со «ШПАЛОЙ» в лице маршрутизации.

Rails предоставляет очень гибкий механизм маршрутизации, основой построения маршрутов является использование ресурсов(resources) и простого задания пути(match) этим двум способам будет уделено наибольшее внимание.

  • Match – простое задание пути, использовать этот способ просто и очень часто люди впервые начинающие использовать Rails не утруждают себя детальным изучением маршрутизации и используют match везде. Я считаю это не совсем правильным раз, и два это приводит к избыточному описанию всех возможных вызовов. Например:
    Есть у нас контроллер User, который содержит действия {index, new, create, show, edit, update, destroy}. Для описания всех этих вызовов мне понадобиться каждый вызов описать в конструкции match.
    match ’/user’=>’user#index’
    match ’/user/new’=>’user#new’
    match ’/user/create/:id’=>’user#create’

    и т.д.
    В принципе можно, но как-то неудобно, во-первых каждое действие, относящееся к одной сущности надо описать отдельной конструкцией match, во-вторых нам известно, что протокол HTTP поддерживает методы отправки запросов {GET, POST, PUT, DELETE}. Не плохо бы нам воспользоваться этими методами и тут мы переходим ко второй конструкции resources.
  • Resources – Это конструкци, которая позволяет быстро и компактно указать маршруты используя HTTP методы {GET, POST, PUT, DELETE}. Например следующая запись resources :users создаст следующие маршруты к контроллеру User:
    Метод HTTP Путь Действие Использовать
    GET /users index Показать весь список пользователей
    GET /users/new new Новый пользователь
    POST /users create Сохранить/создать нового пользователя
    GET /users/:id show Показать пользователя с user.id=:id
    GET /users/:id/edit edit Редактировать пользователя с user.id=:id
    PUT /users/:id update Обновить/сохранить пользователя с user.id=:id
    DELETE /users/:id destroy Удалить пользователя с user.id=:id

    Соответственно и в контроллере User мы должны иметь действия {index, new, create, show, edit, update, destroy}.

    Всё вроде нормально, но давайте рассмотрим ситуацию с личным кабинетом/профилем пользователя, нам надо реализовать доступ к профилю для пользователя, который идентифицировался в системе, если взять маршрут полученный объявлением конструкции resources :users, для доступа к действию show необходимо использовать /user/:id, но зачем нам указывать id когда пользователь идентифицировался в системе и его id уже лежит в cookies, да и вообще было бы лучше перейти не по адресу user/:id а допустим по адресу /profile, тут нам приходит на помощь match, после указания resources :users, пишем match ‘/profile’=>’users#show’, теперь по адресу /profile будет вызван метод show у контроллера users. Удобно, но если мы изначально знаем что работать нам придется с пользователем который будет идентифицирован в системе то можно сделать проще, вместо resources :users пишем resources :user маршруты будут отличаться от тех что были у resources :users.

    Метод HTTP Путь Действие Использовать
    GET /user/new new Новый пользователь
    POST /user create Сохранить/создать нового пользователя
    GET /user show Показать пользователя
    GET /user/edit edit Редактировать пользователя
    PUT /user update Обновить/сохранить пользователя
    DELETE /user destroy Удалить пользователя

    Из всего вышесказанного можно сделать вывод что указывать resources :users – надо работая со списком сущности User и resources :user – для работы с одним экземпляром User.

Теперь сделаем шаг в сторону и посмотрим, как нам эти маршруты использовать в наших приложениях. Можно конечно писать конструкции типа <%=link_to ‘Новый пользователь’, :controller=>:user, :action=>:new %> или <%=link_to ‘Новый пользователь’, ‘/user/new’%> а можно использовать хэлперы, для каждого пути существует функция которая возвращает маршрут к действию. Например для resources :users

Действие Хэлпер
index users_path
new new_user_path
create users_path
show user_path(:id)
edit edit_user_path(:id)
update user_path(:id)
destroy user_path(:id)

Для resources :user

Действие Хэлпер
new new_user_path
create user _path
show user _path
edit edit_user_path
update user _path
destroy user _path

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

class Storage < ActiveRecord::Base
  has_many :products
end
 
class Product < ActiveRecord::Base
  belongs_to :storage
end

в маршрут мы напишем следующий

resources :storages do
  resources :products
end

Таблица маршрутов вложенных ресурсов

Метод HTTP Путь Действие
GET /storages/:storage_id/products index
GET /storages/:storage_id/products/new new
POST /storages/:storage_id/products create
GET /storages/:storage_id/products/:id show
GET /storages/:storage_id/products /:id/edit edit
PUT /storages/:storage_id/products /:id update
DELETE /storages/:storage_id/products /:id destroy

Всё это очень удобно, но возникает вопрос, а ограничены ли мы этими стандартными действиями {index, new, create, show, edit, update, destroy}, например, я решил расширить действия пользователя, добавить ему license в качестве действия показывающего лицензионное соглашение. Мне надо расширить действия resources :user, это можно сделать используя блок member внутри ресурса

resources :user
  member do
    get ‘license’
  end
end

Таким образом появился новый путь /user/license который вызовет действие license в контроллере User. Так же можно использовать методы Post, Put, Delete. Если в блоке member, как и в примере выше, используется только одна строка расширения то можно использовать сокращенную форму записи

resources :user
    get ‘license’, :on=>:member
end

Эта небольшая статья является первой и возможно не последней моей статьей о Routing в Rails, хотелось бы узнать, была ли полезна эта статья и есть ли смысл писать дальше по теме маршрутизации в rails? И конечно конструктивная критика приветствуется!

Автор: Knostan

Источник

Поделиться

* - обязательные к заполнению поля