В том же духе, что и Ришав:
link_to "User Posts", [@user, :posts]
Вот объяснение из моего блога .
В самом начале в Rails вы бы писали маршруты примерно так:
redirect_to :controller => "posts", :action => "show", :id => @post.id
То, что это сделало бы, покорно перенаправляет на действие show
внутри PostsController
и передает параметр id
с
значение того, что @post.id
возвращает. Типичный ответ 302.
Затем появился Rails 1.2 и позволил вам использовать помощников по маршрутизации, например:
redirect_to post_path(@post)
И люди радовались.
Это фактически сделало бы то же самое. post_path
здесь будет построен маршрут с использованием объекта @post
, который будет выглядеть как-то
как /posts/1
, а затем redirect_to
отправит ответ 302 на этот маршрут, и браузер будет следовать по нему.
Затем в более поздних версиях (я не помню, какая из них) допустимый синтаксис был таким:
redirect_to @post
И люди радовались во второй раз.
Волшебство, но не совсем
Любая достаточно продвинутая технология неотличима от магии.
Хотя это похоже на магию, это не так. То, что это делает, на самом деле очень, очень аккуратно. Метод redirect_to
, как и его двоюродные братья link_to
и form_for
, используют общий метод для создания URL-адресов, который называется url_for
. url_for
метод принимает много разных
разнообразные объекты, такие как строки, хэши или даже экземпляры моделей, как в примере выше.
То, что он делает с этими объектами, довольно аккуратно. В случае вызова redirect_to @post
, указанного выше, он проверяет @post
объект, видит, что это объект класса Post
(мы предполагаем, в любом случае) и проверяет, был ли этот объект сохранен в
базу данных где-то, позвонив на нее persisted?
.
Под "постоянством" я подразумеваю, что у объекта Ruby где-то есть соответствующая запись в базе данных. Метод persisted?
в Active Record реализован так:
def persisted?
!(new_record? || destroyed?)
end
Если объект не был создан с помощью вызова, такого как Model.new
, то это не будет новая запись, и если у него не был вызван метод destroy
, он не будет
уничтожен либо. Если оба эти случая верны, то это, скорее всего, означает, что объект был сохранен в базе данных в виде записи.
Если он был сохранен, то url_for
знает, что этот объект можно найти
где-то, и что место, где он может быть найден, скорее всего, под методом post_path
. Так он вызывает этот метод и передает
в значении to_param
этого объекта, которое обычно составляет id
.
Короче говоря, он эффективно делает это:
#{@post.class.downcase}_path(@post.to_param)
Что получается так:
post_path(1)
И когда этот метод вызывается, вы получите эту маленькую строку:
"/posts/1"
симпатичный!
Это называется полиморфная маршрутизация . Вы можете передать объект таким методам, как redirect_to
, link_to
и form_for
, и он будет
попытаться определить правильный URL-адрес того, что использовать.
Форма form_for
Теперь, когда вы кодируете Rails, вы могли использовать form_for
как это очень давно:
<% form_for @post, :url => { :controller => "posts", :action => "create" } do |f| %>
Конечно, с улучшениями в Rails вы можете упростить это до:
<% form_for @post, :url => posts_path do |f| %>
Поскольку форма по умолчанию использует HTTP-метод POST
и, следовательно, запрос к posts_path
отправляется на
create
действие PostsController
, а не index
действие, которое может быть результатом запроса GET
.
Но зачем останавливаться на достигнутом? Почему бы просто не написать это?
<%= form_for @post do |f| %>
Лично я не вижу причин не ... если это так просто. form_for
метод использует url_for
внизу, так же, как
redirect_to
выяснить, куда должна идти форма. Он знает, что объект @post
относится к классу Post
(опять же, мы предполагаем), и он
проверяет, сохранился ли объект. Если это так, то он будет использовать post_path(@post)
. Если нет, то posts_path
.
Сам метод form_for
проверяет, сохраняется ли переданный объект, и если это так, то по умолчанию он будет PUT
HTTP
метод, в противном случае POST
.
Таким образом, form_for
может быть достаточно гибким, чтобы иметь одинаковый синтаксис как для new
, так и edit
. Становится все больше и
в наши дни люди чаще всего помещают свои целые теги form_for
в один частичный и включают его в new
и
edit
стр.
Более сложная форма
Итак, form_for
довольно просто, когда вы передаете нормальный объект, но что произойдет, если вы передадите массив объектов? Как это, для
пример:
<%= form_for [@post, @comment] do |f| %>
Ну, и url_for
, и form_for
ты тоже там прикрыл.
Метод url_for
обнаруживает, что это массив, выделяет каждую часть и проверяет их индивидуально. Во-первых, что это
@post
вещь? Хорошо, в этом случае давайте предположим, что это Post
экземпляр, который сохраняется и имеет идентификатор 1. Во-вторых, что это
@comment
объект? Это экземпляр Comment
, который еще не был сохранен в базе данных.
Что будет делать url_for
, так это построение метода-помощника URL по частям путем помещения каждой части в массив, объединения ее в метод маршрутизации и последующего вызова этого метода маршрутизации с необходимыми аргументами.
Во-первых, он знает, что объект @post
относится к классу Post
и сохраняется, поэтому помощник URL будет начинаться с post
. Во-вторых, он знает, что объект @comment
относится к классу Comment
и не сохраняется, и поэтому comments
будет следовать post
в сборке помощника URL. Части, о которых url_for
теперь знает, это [:post, :comments]
.
Метод url_for
объединяет эти отдельные части с подчеркиванием, так что он становится post_comments
, а затем добавляет _path
до конца этого, в результате post_comments_path
. Затем он передает только сохраненные объекты для вызова этого метода, что приводит к такому вызову:
post_comments_path(@post)
Вызов этого метода приводит к следующему:
"/posts/1/comments"
Лучшая часть? form_for
по-прежнему будет знать, использовать POST
, если объект @comment
не является постоянным объектом, и PUT
, если это так. Хороший
Следует помнить, что form_for
всегда для последнего объекта, указанного в массиве. Объекты до него - это просто его
вложение, ничего более.
Чем больше объектов будет добавлено, тем больше раз url_for
будет проходить трудные дворы и прокладывать путь ... хотя я рекомендую
Вы держите это только на две части.
Символическая форма
Теперь, когда мы рассмотрели использование массива, содержащего объекты для form_for
, давайте рассмотрим другое распространенное использование. Массив, содержащий
хотя бы один объект Symbol, например:
<%= form_for [:admin, @post, @comment] do |f| %>
То, что делает здесь метод url_for
, очень просто. Он видит, что есть Symbol
, и принимает его как есть. Первая часть
url
будет просто совпадать с символом: admin
. URL, который url_for
знает на данный момент, это просто [:admin]
.
Затем url_for
проходит через остальные части массива. В этом случае предположим, что и @post
, и @comment
сохраняются
и что они имеют идентификаторы 1 и 2 соответственно. Те же классы, что и раньше. url_for
затем добавляет post
к URL, который он создает,
и comment
тоже, в результате [:admin, :post, :comment]
.
Затем происходит соединение, в результате чего получается метод admin_post_comment_path
, и поскольку здесь сохраняются как @post
, так и @comment
,
они передаются, что приводит к вызову этого метода:
admin_post_comment_path(@post, @comment)
Который (обычно) превращается в этот путь:
/admin/posts/1/comments/2
Вы можете использовать форму массива полиморфной маршрутизации с методами redirect_to
, link_to
и form_for
. Там, вероятно, другие
методы, которые я сейчас не помню, которые тоже могут это сделать ... это вообще что-то в Rails, которое обычно принимает URL.
Нет необходимости создавать ваши URL-адреса в любой версии Rails больше 2, используя хэши; это довольно старая школа.
Вместо этого поэкспериментируйте с новыми знаниями о полиморфной маршрутизации и используйте их в своих интересах.