Подтвердить что ты не робот

Ruby on Rails: как переопределить маршрут "показать" ресурса?

В настоящее время у меня есть маршрут, который выглядит так:

resources :posts

Я хочу переопределить действие 'show', чтобы я мог отобразить URL-адрес, подобный этому:

posts/:id/:slug

В настоящее время я могу это сделать, добавив пользовательский маршрут match:

resources :posts
match 'posts/:id/:slug' => 'posts#show'

Однако, когда я использую помощник link_to, он не использует мой собственный маршрут показа.

<%= link_to 'show', post %>  # renders /posts/123

Как я могу определить маршрут показа, чтобы я мог использовать помощник link_to?

Обновление:. Как вы можете прочитать в следующих ответах, вы можете переопределить маршрут к действию "показать", но это, вероятно, больше, чем стоит. Легче создать собственный маршрут:

# config/routes.rb
match 'posts/:id/:slug' => 'posts#show', as: 'post_seo'

# app/views/posts/index.html.erb
<%= link_to post.title, post_seo_path(post.id, post.slug) %>
4b9b3361

Ответ 1

У вас есть два маршрута, которые указывают на posts#show (вы должны подтвердить это, запустив rake routes), и ваша ссылка использует неправильный.

Когда вы вызываете link_to('show', post), URL-адрес ссылки генерируется вызовом url_for(post), который (в конце концов, после прохождения нескольких других способов на пути) вызывает post_path(post). Поскольку маршрут до posts#show, созданный вашим вызовом resources(:posts), называется post, это маршрут, который генерирует post_path.

В настоящее время у вас также есть непоследовательные маршруты для показа, обновления и уничтожения действий, которые, вероятно, вызывают проблемы позже.

Вы можете исправить это, изменив маршруты на следующее:

resources :posts, :except => ['show', 'update', 'destroy']
get    'posts/:id/:slug' => 'posts#show', :as => 'post'
put    'posts/:id/:slug' => 'posts#update'
delete 'posts/:id/:slug' => 'posts#destroy'

К сожалению, пока вы еще не можете использовать link_to('show', post), потому что он полагается на возможность использовать post.to_param в качестве единственного аргумента, необходимого для создания пути к сообщению. Для вашего настраиваемого маршрута требуются два аргумента: id и a slug. Итак, теперь ваш код ссылки должен выглядеть так:

link_to 'show', post_path(post.id, post.slug)

Вы можете обойти эту проблему, указав свои собственные post_path и post_url помощники в app/helpers/posts_helper.rb:

module PostsHelper
  def post_path(post, options={})
    post_url(post, options.merge(:only_path => true))
  end

  def post_url(post, options={})
    url_for(options.merge(:controller => 'posts', :action => 'show',
                          :id => post.id, :slug => post.slug))
  end
end

Это означает, что мы, наконец, можем использовать:

link_to 'show', post

Если все это похоже на слишком много работы, обычной альтернативой является использование URL-адресов, которые больше похожи на posts/:id-:slug, и в этом случае вы можете придерживаться стандартных маршрутов RESTful и просто переопределять метод to_param в своем post > класс:

def to_param
  "#{id}-#{slug}"
end

Вам также нужно немного поработать с разделением params[:id] на идентификатор и пул, прежде чем вы сможете найти соответствующий экземпляр в вашем шоу, отредактировать, обновить и уничтожить действия контроллера.

Ответ 2

resources :posts, except: :show do
    get ":slug" => :show, as: "", on: :member
end

и определить вспомогательный

  def post_path post
     "/posts/#{post.id}/#{post.slug}"
  end