Рельсы Sti: один путь, другой контроллер - PullRequest
3 голосов
/ 12 декабря 2011

Есть классы ИППП:

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

Как обрабатывать FirstTypePage с помощью FirstTypePageController, SecondTypePage с помощью SecondTypePageController по одному пути?

1012 * т.е. *

user / 1 / page / 2 обрабатывается: FirstTypePageController, если тип «page 2» - «FirstTypePage», и SecondTypePageController, если тип "page 2" - "SecondTypePage"?

ОБНОВЛЕНИЕ: Мое решение:

  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

Я думаю, что это решение будет работать быстро на небольшом количестве типов страниц, и мы можем управлять размером памяти, используемой для маршрутизации на большом количестве страниц

Ответы [ 2 ]

1 голос
/ 12 декабря 2011

Я вижу один вариант для этого - предварительно загрузить все страницы в routs.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
  // ...

EDIT:

Я только что нашел другое решение, которое могло бы вам помочь - пользовательские ограничения. http://railsdispatch.com/posts/rails-3-makes-life-better

Я не уверен, работает ли это в вашем случае, но я думаю, что стоит больше играть с маршрутами.

0 голосов
/ 12 декабря 2011

вы можете сделать это с before_filter, но разделение моделей STI на разные контроллеры не является хорошим решением.Я полностью согласен со следующей цитатой

Это не всегда применимо, но мне еще предстоит увидеть случай, когда STI хорошо работает с несколькими контроллерами.Если мы используем STI, наши объекты совместно используют набор идентификаторов и атрибутов, и, следовательно, все они должны быть доступны в основном одинаково (найти по некоторому атрибуту, отсортировать по некоторому атрибуту, ограничиться администраторами и т. Д.).Если представление сильно различается, мы можем захотеть визуализировать различные специфичные для модели представления с нашего контроллера.Но если доступ к объекту настолько разный, что он предполагает наличие отдельных контроллеров, то STI, возможно, не был правильным выбором дизайна.

здесь взято http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html

...