Rails中的漂亮(过时)RESTful URL

Paw*_*cki 6 rest url ruby-on-rails slug

我希望我的网站网址看起来像这样:

example.com/2010/02/my-first-post
Run Code Online (Sandbox Code Playgroud)

我的Post模型有slug字段('my-first-post')和published_on字段(我们将从中扣除网址中的年份和月份).

我希望我的Post模型是RESTful,所以url_for(@post)像他们应该的工作,即:它应该生成上述url.

有没有办法做到这一点?我知道你需要覆盖to_parammap.resources :posts使用:requirements选项集,但我无法全部工作.


我几乎完成了,我90%在那里.使用resource_hacks插件我可以实现这个目的:

map.resources :posts, :member_path => '/:year/:month/:slug',
  :member_path_requirements => {:year => /[\d]{4}/, :month => /[\d]{2}/, :slug => /[a-z0-9\-]+/}

rake routes
(...)
post GET    /:year/:month/:slug(.:format)      {:controller=>"posts", :action=>"show"}
Run Code Online (Sandbox Code Playgroud)

并在视图中:

<%= link_to 'post', post_path(:slug => @post.slug, :year => '2010', :month => '02') %>
Run Code Online (Sandbox Code Playgroud)

生成适当的example.com/2010/02/my-first-post链接.

我也想这样做:

<%= link_to 'post', post_path(@post) %>
Run Code Online (Sandbox Code Playgroud)

但它需要覆盖to_param模型中的方法.应该相当容易,除了事实,to_param必须返回String,而不是Hash我喜欢它.

class Post < ActiveRecord::Base
  def to_param
   {:slug => 'my-first-post', :year => '2010', :month => '02'}
  end
end
Run Code Online (Sandbox Code Playgroud)

导致can't convert Hash into String错误.

这似乎被忽略了:

def to_param
  '2010/02/my-first-post'
end
Run Code Online (Sandbox Code Playgroud)

因为它导致错误:( post_url failed to generate from {:action=>"show", :year=>#<Post id: 1, title: (...)它错误地将@post对象分配给:year键).我对如何破解它毫无头绪.

Paw*_*cki 5

Rails 3.x 和 Rails 2.x 的漂亮 URL,无需任何外部插件,但不幸的是,有一些 hack。

路线.rb

map.resources :posts, :except => [:show]
map.post '/:year/:month/:slug', :controller => :posts, :action => :show, :year => /\d{4}/, :month => /\d{2}/, :slug => /[a-z0-9\-]+/
Run Code Online (Sandbox Code Playgroud)

应用程序控制器.rb

def default_url_options(options = {})
  # resource hack so that url_for(@post) works like it should
  if options[:controller] == 'posts' && options[:action] == 'show'
    options[:year] = @post.year
    options[:month] = @post.month
  end
  options
end
Run Code Online (Sandbox Code Playgroud)

后rb

def to_param # optional
  slug
end

def year
  published_on.year
end

def month
  published_on.strftime('%m')
end
Run Code Online (Sandbox Code Playgroud)

看法

<%= link_to 'post', @post %>
Run Code Online (Sandbox Code Playgroud)

请注意,对于 Rails 3.x,您可能需要使用以下路由定义:

resources :posts
match '/:year/:month/:slug', :to => "posts#show", :as => :post, :year => /\d{4}/, :month => /\d{2}/, :slug => /[a-z0-9\-]+/
Run Code Online (Sandbox Code Playgroud)

有没有徽章可以回答您自己的问题?;)

顺便说一句:routing_test文件是查看 Rails 路由功能的好地方。

更新:使用default_url_options是一条死胡同@post仅当控制器中定义了变量时,发布的解决方案才有效。例如,如果存在@posts带有帖子数组的变量,我们就不走运了(因为default_url_options无法访问视图变量,例如p@posts.each do |p|.

所以这仍然是一个悬而未决的问题。有人帮忙吗?


Paw*_*cki 4

它仍然是一个 hack,但可以执行以下操作:

application_controller.rb

def url_for(options = {})
  if options[:year].class.to_s == 'Post'
    post = options[:year]
    options[:year] = post.year
    options[:month] = post.month
    options[:slug] = post.slug
  end
  super(options)
end
Run Code Online (Sandbox Code Playgroud)

以下内容将起作用(在 Rails 2.3.x 和 3.0.0 中):

url_for(@post)
post_path(@post)
link_to @post.title, @post
etc.
Run Code Online (Sandbox Code Playgroud)

这是一些好人对我的类似问题的回答,自定义 RESTful 资源的 url_for (复合键;不仅仅是 id)