2013-03-13 104 views
5

我在Rails应用程序中使用了许多不同的模型。我见过许多网站使用应用程序范围的段塞路由方法。这是什么意思?如何为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和应用程序中创建读者喜爱的蛞蝓,但我不知道的方法有root级别的蛞蝓为各种不同的物体。您可以将其视为与Facebook的Graph API类似:存在不同的对象类型,但所有对象类型都存在于https://graph.facebook.com/object-id

任何洞察将非常感谢!

+0

hmm。你可能有一张slu table子的桌子,你可以保留它的类型。那么只需添加一个检查该类型的路由并尝试基于该路由重定向。 – jvnill 2013-03-13 01:08:26

+0

这似乎有点过分,因为现在我需要提出两个请求来获取对象,不是吗? – 2013-03-13 01:09:27

+0

是。我不知道Rails如何区分slu unless,除非它们已经被定义,或者至少有一些可以区分它们的模式。 – jvnill 2013-03-13 01:15:21

回答

10

可能有办法做到这一点与freindly_id,但我认为与友好id的问题是事物的范围由模型。

如果我想要真正地在网站范围内猛击,我会创建一个与我的模型有多态关系的slu table表。

Sluggable_type和sluggable_id然后一个slug字段与完整的永久链接/ slug。

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

现在我能做的做一个通配符包罗万象的路线或运行时创建了我所有的蛞蝓的路线和强制路由刷新当模型更新,这是该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 

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!

编辑任何猛击记录刷新路由表之后。

我们遇到了类似的问题,我们可能会试着用这种方法来试试。

+0

该死的,打我在我写作时类似的答案。不过,看起来您的路由方法可能比我的天真方法更深思熟虑。 – imakewebthings 2013-03-13 19:18:48

+0

我们在生产中使用它,虽然只用于页面,但我认为它应该像这样扩展?这很好,因为你看到'rake routes'中所有的段落路线# – 2013-03-13 19:19:57

+0

@j_mcnally,你使用生产中的第一个还是第二个版本?第二种方法出现WAYYYY更干净。当我必须从控制器方法中加载另一个控制器时,它变得非常脏。我在这里想到的一个例外可能会创建一个名为SluggedController的中间控制器,该控制器继承了ApplicationController的子类,然后为其他控制器子类SluggedController。好奇地在这里得到你的想法! – 2013-03-14 18:28:37

2

我可能会接近这个如下,至少在第一遍:

  • 使用friendly_id或类似蛞蝓产生每个模型涉及
  • 胡克一个包罗万象的路线/([-_a-zA-Z0-9]+)和它指向像EntitiesController#show
  • 胡克为/developers指向更高的优先级路线Users#index
  • 在EntitiesController#显示:

    @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我很想知道更好的方法来解决这个问题;这只是我最初如何解决问题。

+0

感谢凯尔!我已经upvoted你的答案,但我在等待,看看还有什么我得到...试图找到最好的办法在这里:) – 2013-03-13 18:48:48

0

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

belongs_to :sluggable, :polymorphic => true 

在至少该表将有:

  • value - 或者比这一些更好的名字。 slu itself本身的价值。
  • sluggable_type and sluggable_id - 多态外键。

你的公司,用户等车型车型只会有一个毛坯:

has_one :slug 

这给我们了蝙蝠的几个优点:

  • 它现在容易做出对slug值有独特的限制。如果slu were被保留为所有不同可缓存模型的属性,那么您的唯一约束将不得不检查所有其他可坍缩表的唯一性。造成一段糟糕的时光。
  • 路由很简单,因为您可以使用正常的resource路由脱离根级别名称空间。您可能希望将其保持在路由文件的最终位置,尽管其他更具体的路由优先。 编辑:这种路由基本上是j_mcnally建议的第一种路由方法。
  • 所有的slu logic logic logic,like like like what what what what is is is is is is is is is this this this this this this this this良好的问题分离而不是污染用户模型。特别是如果slu rules的规则对每个人都是一样的,就像他们在这里一样。

就控制器的工作方式而言,我会选择Kyle所说的,然后键入sluggable_type字段以找到要渲染的视图。