【问题标题】:Rails Sti: single path, different controllerRails Sti:单路径,不同的控制器
【发布时间】:2011-12-12 14:57:57
【问题描述】:

有 STI 课程:

class Page < ActiveRecord::Base
  belongs_to :user
end

class FirstTypePage < Page
end

class SecondTypePage < Page
end

每个类的控制器,

class PageController < AplicationCorroller
end

class FirstTypePageController < PageController
end

class SecondTypePageController < PageController
end

和路由:

resources :user
  resource :page
end

单路径下FirstTypePageController如何处理FirstTypePage,SecondTypePageController如何处理SecondTypePage?

user/1/page/2 由以下人员处理: FirstTypePageController 如果“page 2”类型是“FirstTypePage”, 如果“page 2”类型是“SecondTypePage”,则通过 SecondTypePageController ?

更新:我的解决方案:

  match 'user/:user_id/page/:action',
    :controller=>'page/first_type_page',
    :constraints=>PageConstraints.new('FirstTypePage')
  match 'user/:user_id/page/:action',
    :controller=>'page/second_type_page',
    :constraints=>PageConstraints.new('SecondTypePage')

class PageConstraints

  @@cache ||= {}

  def initialize o_type
    #@mutex = Mutex.new
    @o_type = o_type
  end

  def matches?(request)
    user_id = request.params[:user_id]
    #add Mutex lock here
    unless page_type = @@cache[user_id]
      page_type = User.find(user_id).do_some_magik_to_suggest_type
      @@cache[page_id] = page_type
      @@cache.shift if @@cache.size > 1000
    end
    page_type == @o_type
  end

end

我认为这个解决方案在少量页面类型上运行很快,我们可以管理内存大小,用于大量页面上的路由

【问题讨论】:

  • 也就是说,可以在路由层级中为Controller在runtime中选择。类似 :controller=>User.controller_for_page(:user_id)??

标签: ruby-on-rails ruby routing sti


【解决方案1】:

我可以看到一个选项 - 在 routes.rb 中预加载所有页面并为每个页面定义特殊路由。

resources :users do |user|
  Page.all do |page|
    if page.first_type?
      # ... routes to first_type_page_controller
    else
      # ...
  end
end

另一种解决方案是在PageController 中使用策略模式(无需使用FirstTypePageController 等)。

pages_controller.rb:

before_filter :choose_strategy

def show
  @strategy.show
end

private

def choose_strategy
  @strategy = PagesControllerStrategy.new(self, page)
end

def page
  @page ||= Page.find params[:id]
end

pages_controller_strategy.rb:

class PagesControllerStrategy

  def initialize(controller, page)
    @controller = controller
    @page = page
  end

  def show
    # do what you what with controller and page
  end
end

但是,我建议您仅在视图级别拆分行为:

show.html.haml:

- if page.first_type?
  = render 'pages/first_type'
- else
  // ...

编辑:

我刚刚找到了另一个可以帮助您的解决方案 - 自定义约束。 http://railsdispatch.com/posts/rails-3-makes-life-better

我不确定这是否适用于您的情况,但我认为更多地使用路线是值得的。

【讨论】:

  • “为每个页面定义特殊路由” - 我认为,它会在大量页面上表现不佳,并且占用大量内存
  • 在第二个解决方案中,我们失去了所有的 ActionController 魔法,比如过滤器和其他
  • 这就是为什么我更喜欢在视图中拆分逻辑。
  • 我刚刚找到了更好的解决方案,可能。请参阅我的答案中的编辑。
【解决方案2】:

您可以使用 before_filter 来做到这一点,但是将 STI 模型分成不同的控制器并不是一个好的解决方案。我完全同意下一个报价

这可能并不总是适用,但我还没有看到 STI 与多个控制器一起工作的案例。如果我们使用 STI,我们的对象共享一组 ID 和属性,因此都应该以基本相同的方式访问(按某些属性查找、按某些属性排序、限制为管理员等)。如果显示变化很大,我们可能希望从我们的控制器呈现不同的特定于模型的视图。但如果对象访问变化如此之大以至于它建议使用单独的控制器,那么 STI 可能不是正确的设计选择。

在这里http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html

【讨论】:

  • 您的意思是使用 before_filter 重定向到适当的控制器?可以在路由中完成吗?
  • 我同意这句话,购买多态模型我也会遇到同样的路由问题。
  • 是的,如果您需要自动检测路由中的模型类型,在过滤重定向之前,我认为这是不可能的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 2021-05-27
  • 1970-01-01
  • 2019-01-12
相关资源
最近更新 更多