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?
ie
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
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.
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.