给出以下资源定义:
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 bug ...)。但我可以为我做这项工作吗?我要补充说,弄乱default_url_options
是一个死胡同。
仅在Rails 3.x中工作的解决方案没问题,但我不想使用任何插件。
答案 0 :(得分:7)
覆盖to_param
。 to_param
的默认值是记录ID,但您可以更改它。
class Post
def to_param
"/#{year}/#{month}/#{slug}"
end
end
(这假设您在Post
班级中有year
,month
和slug
的方法。)
现在生成网址时,系统会调用被覆盖的to_param
。
<%= link_to @post.title, @post %>
=> <a href="/2010/02/foobar">Foobar</a>
显然你必须确保你的PostsController show动作可以根据传递的参数找到记录。
您可能需要更改路线定义并消除此路线:
map.post '/:year/:month/:slug, :controller => :posts, :action => :show
但是,如果to_param
被覆盖,默认的RESTful post_path
对于您要生成的网址就可以正常使用。
答案 1 :(得分:6)
如何为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
答案 2 :(得分:3)
不幸的是,当您将ActiveRecord传递给link_to
时,它会尝试使用Polymorphic URL帮助程序来生成链接的URL。
Polymorphic URL帮助程序仅用于通过使用ActiveRecord的记录标识符生成RESTful URL。
由于您的路由使用Post对象的多个属性,因此Polymorphic URL帮助程序无法生成正确的URL ...而不是作为限制的错误:)
深入研究link_to
,当你传递哈希时,它不会使用多态路由,所以你可以避免整个问题。
我认为一种hacky方法是在Post上定义一个名为routing_hash
的方法,该方法返回
(:year => post.year, :month => post.month, :slug => post.slug)
我很欣赏它不是干眼的方法,但它是我现在能想到的最好的方法
答案 3 :(得分:0)
我正在尝试TempoDB并使用以下工作扩展他们的课程。我有路由“资源:系列”,然后可以使用url_for没有问题。
class TempoDB::Series
def self.model_name
ActiveModel::Name.new(TempoDB::Series,nil,'series')
end
def to_param
self.key
end
end