如何为Rails应用程序创建应用程序范围的slug路由?

时间:2013-03-13 01:05:41

标签: ruby-on-rails ruby-on-rails-3 url-routing rails-routing

我正在开发的Rails应用程序中有许多不同的模型。我见过许多网站都使用了应用程序范围的slug路由方法。这是什么意思?

http://example.com/nick-oneill <-- This points to a User object
http://example.com/facebook    <-- This points to a Company object
http://example.com/developers  <-- This points to the users#index page

我知道to_param并在应用程序中创建了读者友好的slug,但是我不知道有一种方法可以为各种对象提供根级别的slu ..你可以认为这类似于Facebook的Graph API:有不同的对象类型,但它们都存在于https://graph.facebook.com/object-id

非常感谢任何见解!

3 个答案:

答案 0 :(得分:10)

使用freindly_id可能有一种方法可以做到这一点,但我认为友好id的问题是由模型确定的范围。

如果我真的希望在整个网站上进行阻塞,我会创建一个与我所有模型具有多态关系的slugs表。

Sluggable_type和sluggable_id,然后是一个带有完整永久链/ slug的slug字段。

+---------------------------------------------+
| sluggable_type | sluggable_id |     slug    |
|      user      |       13     |  users/john |
+---------------------------------------------+

现在我可以做一个通配符捕获所有路由或在运行时为我的所有slug创建路由,并在更新模型更新时强制路由刷新。

routes.rb

  get "/*segments",
               :controller => 'slugs',
               :action => 'dynamicroute'

现在在你的SlugsController中实现一个类似

的方法
def dynamicroute
  segments = params[:segments]
  slugs.find_by_slug(segments)
  slug.sluggable_type.constantize.find(slug.sluggable_id) #retrive real record
  #some magic to handle the slugged item maybe redirect to the appropriate
  #controller or somehow call the show view for that controller
end

OR

routes.rb

begin  
  Slug.all.each do |s|
    begin
      get "#{s.slug}" => "#{s.sluggable_type.demodulize.pluralize.camelize}#show"
    rescue
    end
  end
rescue
end

如果您使用第二种方法进行路由,请务必致电

YOUR_APP_NAME::Application.reload_routes!

编辑任何slugged记录后刷新路由表。

我们遇到过类似的问题,我们可能会尝试这种方法。

答案 1 :(得分:2)

我可能会按如下方式处理,至少作为第一遍:

  • 使用friendly_id或类似方法为每个涉及的模型生成slug
  • 连接/([-_a-zA-Z0-9]+)的全能路线并将其指向EntitiesController#show
  • 为指向/developers
  • Users#index建立更高优先级的路线
  • 在EntitiesController中#show:

    @entity = User.find(params[:id]) or Company.find(params[:id]) or raise ActionController::RoutingError.new('Not Found')

  • 然后,根据你所拥有的实体类型:

    render "VIEW_PATH_BASED_ON_ENTITY_CLASS/show"

我还会从大多数到最不经常访问的顺序排序(首先猜测,然后再使用数据来调整顺序)。

最后,可能很明显,但请确保您正在为每个表中的slug列编制索引,因为您经常会为每个请求执行多次查找。

FWIW我也想知道更好的方法来解决这个问题;这就是我最初如何解决问题的方法。

答案 2 :(得分:0)

我的第一反应是创建一个新的Slug模型。此模型将具有多态belongs_to

belongs_to :sluggable, :polymorphic => true

至少这个表会有:

  • value - 或者更好的名字。 slu its本身的价值。
  • sluggable_typesluggable_id - 多态外键。

您的公司,用户等型号模型只会有一个slu ::

has_one :slug

这给了我们一些优势:

  • 现在很容易对slug值进行唯一约束。如果slug被保存为所有不同可缓冲模型的属性,那么您的唯一约束必须检查所有其他可缓冲表的唯一性。这是一段糟糕的时光。
  • 路由非常简单,因为您可以使用根级别名称空间之外的正常resource路由。您可能希望将其保留在路径文件的低端/末端,因此其他更具体的路由优先。 修改:此路由基本上是j_mcnally建议的第一个路由方法。
  • 一个slug的所有逻辑,就像制作一个有效的slug一样,保留在这个模型中。关注点的良好分离而非污染表示用户模型。特别是如果每​​个人的slu the规则与他们在这里相同。

就控制器的工作方式而言,我会选择Kyle所说的并关闭sluggable_type字段来查找要渲染的视图。