url_for пользовательского ресурса RESTful (составной ключ; не просто идентификатор) - PullRequest
9 голосов
/ 15 февраля 2010

Учитывая следующее определение ресурса:

map.resources :posts, :except => [:show]
map.post '/:year/:month/:slug, :controller => :posts, :action => :show

Я могу заставить url_for работать на меня, используя этот синтаксис:

<%= link_to @post.title, post_url(:year => '2010', :month => '02', :slug => 'test') %>

Но есть ли способ заставить это работать?

<%= link_to @post.title, @post %>

В настоящее время выдает эту ошибку:

No route matches {:year=>#<Post id: 1, title: "test", (...)>, :controller=>"posts", :action=>"show"}

По-видимому, он передает объект @post первому параметру маршрута (похоже на ошибку Rails ...). Но могу ли я сделать эту работу для меня? Добавлю, что возиться с default_url_options - это тупик.

Решение, работающее только в Rails 3.x, в порядке, но я бы предпочел не использовать никаких плагинов.

Ответы [ 4 ]

7 голосов
/ 18 февраля 2010

Переопределить to_param. Значением по умолчанию для to_param является идентификатор записи, но вы можете изменить его.

class Post
  def to_param
    "/#{year}/#{month}/#{slug}"
  end
end

(Предполагается, что у вас есть методы в классе Post для year, month и slug.)

Теперь, когда сгенерированы URL-адреса, будет вызываться ваше переопределенное значение to_param.

<%= link_to @post.title, @post %> 
    => <a href="/2010/02/foobar">Foobar</a>

Очевидно, вы должны убедиться, что ваше действие ShowController может найти запись на основе параметров, переданных ей.

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

map.post '/:year/:month/:slug, :controller => :posts, :action => :show

Однако при переопределении to_param значение RESTful по умолчанию post_path будет отлично работать для URL, которые вы хотите сгенерировать.

6 голосов
/ 24 февраля 2010

Как насчет исправления url_for для PostsController? Может быть не очень элегантно, но оно СУХОЕ, и все должно работать.

# app/controllers/posts_controller.rb 
class PostsController < ApplicationController

  protected

    def url_for(options = {} )
      if options[:year].class.to_s == "Post"
        obj = options[:year]
        options[:year] = obj.year
        options[:month] = obj.month
        options[:slug] = obj.slug
      end
      super(options)
    end

end
3 голосов
/ 18 февраля 2010

К сожалению, когда вы передаете ActiveRecord в link_to, он пытается использовать полиморфные URL-помощники для генерации URL-адреса для ссылки.

Полиморфные URL-помощники предназначены только для генерации RESTful URL-адресов с использованием идентификатора записи вашего ActiveRecord.

Поскольку в вашем маршруте используется несколько атрибутов объекта Post, помощники по Полиморфному URL не могут генерировать правильный URL ... не столько ошибка, сколько ограничение:)

Вводя в link_to, когда вы передаете ему хэш, он не использует полиморфную маршрутизацию, поэтому вы избегаете всей проблемы.

Я полагаю, что хакерский подход заключается в определении метода на Post с именем routing_hash, который возвращает

(:year => post.year, :month => post.month, :slug => post.slug)

Я ценю, что это не СУХОЙ подход, но это лучшее, что я могу придумать на данный момент

0 голосов
/ 11 марта 2014

Я пробовал TempoDB и расширение их класса с помощью приведенного ниже работало для меня.У меня был маршрут "resources: series", и я мог без проблем использовать url_for.

class TempoDB::Series
  def self.model_name
    ActiveModel::Name.new(TempoDB::Series,nil,'series')
  end
  def to_param
    self.key
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...