繁体   English   中英

Rails中的漂亮(过时)RESTful URL

[英]Pretty (dated) RESTful URLs in Rails

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

example.com/2010/02/my-first-post

我的Post模型有slug字段('my-first-post')和published_on字段(我们将从中扣除url中的年份和月份部分)。

我希望我的Post模型是RESTful的,所以url_for(@post)类的东西就像它们应该的那样工作,即:它应该生成上面提到的url。

有没有办法做到这一点? 我知道你需要覆盖to_param并拥有map.resources :posts with :requirements map.resources :posts选项设置,但我无法全部工作。


我几乎完成了,我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"}

并在视图中:

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

生成正确的example.com/2010/02/my-first-post链接。

我也想这样做:

<%= link_to 'post', post_path(@post) %>

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

class Post < ActiveRecord::Base
  def to_param
   {:slug => 'my-first-post', :year => '2010', :month => '02'}
  end
end

结果can't convert Hash into String错误。

这似乎被忽略了:

def to_param
  '2010/02/my-first-post'
end

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

Rails 3.x和Rails 2.x的漂亮网址,不需要任何外部插件,但遗憾的是有点破解。

的routes.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\-]+/

application_controller.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

post.rb

def to_param # optional
  slug
end

def year
  published_on.year
end

def month
  published_on.strftime('%m')
end

视图

<%= link_to 'post', @post %>

注意,对于Rails 3.x,您可能希望使用此路由定义:

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

是否有任何徽章可以回答您自己的问题? ;)

顺便说一句: routing_test文件是一个很好的地方,可以看看你可以用Rails路由做什么。

更新:使用default_url_options是一个死胡同 只有在控制器中定义了@post变量时,发布的解决方案才@post 如果有,例如, @posts变量与岗位的阵列,我们的运气(becase的default_url_options没有权限查看变量,如p@posts.each do |p|

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

它仍然是一个黑客,但以下工作:

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

以下将适用(在Rails 2.3.x和3.0.0中):

url_for(@post)
post_path(@post)
link_to @post.title, @post
etc.

这是一个很好的灵魂对我的类似问题的答案, url_for自定义RESTful资源(复合键;不仅仅是id)

Ryan Bates在他的屏幕演员中谈到了它“如何添加自定义路线,使一些参数可选,并添加其他参数的要求。” http://railscasts.com/episodes/70-custom-routes

这可能会有所帮助。 您可以在ApplicationController中定义default_url_options方法,该方法接收传递给url帮助程序的Hash of options并返回要用于这些URL的其他选项的Hash。

如果将post作为post_path的参数post_path ,则将其分配给路径的第一个(unnassigned)参数。 没有测试过,但它可能有效:

def default_url_options(options = {})
  if options[:controller] == "posts" && options[:year].is_a?Post
    post = options[:year]
    {
      :year  => post.created_at.year,
      :month => post.created_at.month,
      :slug  => post.slug
    }
  else
    {}
  end
end

我处于类似的情况,其中一个帖子有一个语言参数和slug参数。 编写post_path(@post)将此哈希发送到default_url_options方法:

{:language=>#<Post id: 1, ...>, :controller=>"posts", :action=>"show"}

更新:有一个问题,你不能覆盖该方法的url参数。 传递给url帮助程序的参数优先。 所以你可以这样做:

post_path(:slug => @post)

和:

def default_url_options(options = {})
  if options[:controller] == "posts" && options[:slug].is_a?Post
    {
      :year  => options[:slug].created_at.year,
      :month => options[:slug].created_at.month
    }
  else
    {}
  end
end

如果Post.to_param返回了slug,这将有效。 您只需要在哈希中添加年份和月份。

你可以节省压力并使用friendly_id 它真棒,做到了这一点,你可以看一下Ryan Bates 的截屏视频来开始。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM