Rails Sti: single path, different controller

匿名 (未验证) 提交于 2019-12-03 01:39:01

问题:

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



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!