5

我正在开发的 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,但是我不知道为各种对象提供根级 slug 的方法。你可以认为这类似于 Facebook 的 Graph API:有不同的对象类型,但它们都存在于https://graph.facebook.com/object-id

任何见解将不胜感激!

4

3 回答 3

10

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

如果我想要真正的站点范围的 slugging,我会创建一个与我的所有模型具有多态关系的 slugs 表。

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

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

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

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

或者

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 记录以刷新路由表后。

我们也遇到过类似的问题,我们可能会尝试对这种方法进行优化。

于 2013-03-13T19:04:21.090 回答
2

我可能会这样处理,至少作为第一遍:

  • 使用friendly_id 或类似的为每个涉及的模型生成slugs
  • 连接一条包罗万象的路线/([-_a-zA-Z0-9]+)并将其指向类似的东西EntitiesController#show
  • 连接更高优先级的路由以/developers指向Users#index
  • 在 EntityController#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我也很想知道一种更好的方法来解决这个问题;这就是我最初解决问题的方式。

于 2013-03-13T18:09:52.073 回答
0

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

belongs_to :sluggable, :polymorphic => true

至少这张桌子会有:

  • value- 或者比这更好的名字。蛞蝓本身的价值。
  • sluggable_typesluggable_id- 多态外键。

您的公司、用户等模型模型只会有一个 slug:

has_one :slug

这给了我们一些优势:

  • 现在很容易对 slug 值进行唯一约束。如果 slug 被保留为所有不同 sluggable 模型的属性,则您的唯一约束将必须检查所有其他 sluggable 表的唯一性。造成不好的时候。
  • 路由很简单,因为您可以使用resource根级命名空间之外的普通路由。您可能希望将其保持在路由文件的低位/末尾,以便其他更具体的路由优先。编辑:这个路由基本上是 j_mcnally 建议的第一个路由方法。
  • 一个 slug 的所有逻辑,就像一个有效的 slug 一样,都保存在这个模型中。良好的关注点分离而不是污染说用户模型。特别是如果每​​个人的蛞蝓规则都和这里一样。

就控制器的工作方式而言,我会按照 Kyle 所说的进行,然后关闭sluggable_type字段以找到您想要渲染的视图。

于 2013-03-13T19:13:57.413 回答