可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Have STI classes:
class Page < ActiveRecord::Base belongs_to :user end class FirstTypePage < Page end class SecondTypePage < Page end
Controllers for each class,
class PageController < AplicationCorroller end class FirstTypePageController < PageController end class SecondTypePageController < PageController end
And routings:
resources :user resource :page end
How to handle FirstTypePage by FirstTypePageController, SecondTypePage by SecondTypePageController on single path?
i.e.
user/1/page/2 is handled by: FirstTypePageController if "page 2" type is "FirstTypePage", and by SecondTypePageController if "page 2" type is "SecondTypePage" ?
UPDATE: My solution:
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
I think this solution will work fast on a small amount of page types, and we can manage memory size, used for routings on a large amount of pages
回答1:
I can see one option to do that - preload all pages in the routes.rb and define special routes for each page.
resources :users do |user| Page.all do |page| if page.first_type? # ... routes to first_type_page_controller else # ... end end
Another solution could be to use strategy patter in the PageController
(no need to use FirstTypePageController and other).
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
However, I'd suggest you to split the behavior on the view level only:
show.html.haml:
- if page.first_type? = render 'pages/first_type' - else // ...
EDIT:
I just found another solution, that could help you - custom constraints. http://railsdispatch.com/posts/rails-3-makes-life-better
I'm not sure if that works in your case, but I think it is worth to play with routes more.
回答2:
you can do it with before_filter, but separating STI models into different controllers isn't good solution. I totally agree with next quote
This may not always apply, but I have yet to see a case where STI works well with multiple controllers. If we are using STI, our objects share a set of IDs and attributes, and therefore should all be accessed in basically the same way (find by some attribute, sort by some attribute, restrict to administrators, etc). If presentation varies greatly we may want to render different model-specific views from our controller. But if object access varies so much that it suggests separate controllers, then STI may not have been the correct design choice.
took here http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html