rails路由上多个控制器的根路径

时间:2012-03-31 10:17:29

标签: ruby-on-rails-3 ruby-on-rails-3.1

我有两个资源控制器,我使用slug来表示ID。 (friendly_id gem)。

我能够在路线上获得一个资源的显示路径,但不能同时拥有两个资源。即

root :to => 'home#index'
match '/:id' => "properties#show"
match '/:id' => "contents#show"

基本上我想要网址,

# Content
domain.com/about-us
domain.com/terms
# Property
domain.com/unique-property-name
domain.com/another-unique-property-name

无论我在顶级作品上投入什么资源。有没有办法做到这一点?

如果你能提供帮助,谢谢。

5 个答案:

答案 0 :(得分:5)

这是未经测试的,但请尝试在路线上使用constraint

root :to => 'home#index'
match '/:id', :to => "properties#show",
              :constraints => lambda { |r| Property.find_by_id(r.params[:id]).present? }
match '/:id', :to => "contests#show",
              :constraints => lambda { |r| Contest.find_by_id(r.params[:id]).present? }

或者,您可以创建一个响应matches?的单独类,而不是定义lambda proc。 (我建议将这些类放入可在Rails应用程序中自动加载的单独文件中。)

# app/constraints/property_constraint.rb
class PropertyConstraint
  def self.matches?(request)
    property = Property.find_by_id(request.params[:id])
    property.present?
  end
end

# app/constraints/contest_constraint.rb
class ContestConstraint
  def self.matches?(request)
    contest = Contest.find_by_id(request.params[:id])
    contest.present?
  end
end

# config/routes.rb
root :to => 'home#index'
match '/:id', :to => "properties#show", :constraints => PropertyConstraint
match '/:id', :to => "contests#show", :constraints => ContestConstraint

不幸的是,这会产生额外的数据库查询(一次在路由中,在控制器中再次出现)。如果有人建议尽量减少这个,请分享。 :)

答案 1 :(得分:2)

此Rails引擎可以满足您的需求:

Slug Engine at Github

基本上,作者的方法是在他的主应用程序中安装Rails引擎。该引擎既包含一个控制器,用于处理存在的slu and,也包含一个中间件,用于过滤和弃用不存在的slu ..

他解释了为什么他在一个相当详细和有趣的blog post中采用了这种方法和其他流产的解决方案。这篇博客文章和slug引擎源代码应该足以让你自己编写和运行代码,但是如果你想要一个直接的解决方案,这个开源引擎似乎正是你正在寻找的。< / p>

答案 2 :(得分:1)

您可以在中间件

中执行此操作
  1. 检测路径中的slu <
  2. 如果存在此slug的内容 - 将请求路径更改为“contents /:id”
  3. 如果存在此slug的Property - 将请求路径更改为“properties /:id”
  4. 路由集中的
  5. 匹配'contents /:id'=&gt; “属性#秀”

    匹配'properties /:id'=&gt; “内容#显示”

答案 3 :(得分:1)

您可以编写另一个控制器,它从路由器获取id并检查id是属于属性还是内容并呈现相应的视图。

match '/:id' => "router#show"

控制器将执行以下操作:

def show
    @property = Property.find(params[:id])
    if @property then
        render 'property/show'
    else
        @content = Content.find(params[:id])
        render 'content/show
    end
end

我没有测试过这段代码,但这个想法应该可行。

答案 4 :(得分:0)

如果可能的话,我建议您以更加RESTful的方式执行此操作。基本上,您有两种不同的资源,您应该将它们分开:

match 'properties/:id' => "properties#show"
match 'contents/:id'   => "contents#show"

这将为您带来许多优势。一个直接的好处是,您可以避免属性和内容的ID之间的冲突。 (请注意,friendly_id不会帮助您解决原始方案中的模型间冲突问题。)