Один контроллер, несколько (унаследованных) классов (рельсы 3) - PullRequest
8 голосов
/ 24 февраля 2011

У меня есть базовый класс, унаследованный от 2 других через наследование одной таблицы.Я хочу, чтобы все подклассы совместно использовали один и тот же контроллер / представления по разным причинам - единственное реальное различие заключается в функциональности модели.

Однако, когда я пытаюсь использовать link_to "вещи", instance_of_child , я получаю жалобы на невозможность найти правильную страницу.

Я пробовал возиться с match '/ subclass' => redirect ('/ parent') , но это приводит к странным ссылкам, которые не имеют смысла.Какие-либо предложения?Я довольно новичок в рельсах, и я признаю, что мое понимание route.rb все еще ограничено, однако я не совсем уверен, что даже там, где я должен искать.

1 Ответ

13 голосов
/ 24 февраля 2011

С http://www.alexreisner.com/code/single-table-inheritance-in-rails:

Если вы когда-либо пытались добавить STI в существующее приложение Rails, вы, вероятно, знаете, что многие из ваших методов link_to и form_for выдают ошибки при добавлении родительского класса.Это связано с тем, что ActionPack просматривает класс объекта, чтобы определить его путь и URL, а вы не сопоставили маршруты для своих новых подклассов.Вы можете добавить маршруты так, хотя я не рекомендую это:

# NOT recommended:
map.resources :cars,        :as => :vehicles, :controller => :vehicles
map.resources :trucks,      :as => :vehicles, :controller => :vehicles
map.resources :motorcycles, :as => :vehicles, :controller => :vehicles

Это только смягчает определенный симптом.Если мы используем form_for, наши поля формы по-прежнему не будут иметь ожидаемых имен (например: params [: car] [: color] вместо params [: vehicle] [: color]).Вместо этого мы должны атаковать корень проблемы, реализовав метод model_name в нашем родительском классе.Я не видел никакой документации по этой технике, так что она очень неофициальная, но она имеет смысл и прекрасно работает для меня в Rails 2.3 и 3:

def self.inherited(child)  
  child.instance_eval do
    def model_name
      Vehicle.model_name
    end
  end
  super 
end

Это, вероятно,выглядит странно, поэтому позвольте мне объяснить:

Когда вы вызываете метод генерирования URL (например, link_to ("car", car)), ActionPack вызывает model_name для класса данного объекта (здесь car).Это возвращает специальный тип строки, которая определяет, как объект вызывается в URL.Все, что мы здесь делаем, это переопределение метода model_name для подклассов Vehicle, поэтому ActionPack будет видеть подклассы Car, Truck и Motorcycle как принадлежащие родительскому классу (Vehicle), и, таким образом, будет использовать именованные маршруты родительского класса (VehiclesController) везде, где есть URL-адреса.генерироваться.Все это при условии, что вы используете URL-адреса в стиле ресурсов Rails (RESTful).(Если это не так, пожалуйста.)

Чтобы самостоятельно исследовать вызов model_name, см. Исходный код Rails для метода ActionController :: RecordIdentifier # model_name_from_record_or_class.В Rails 2.3 специальная строка является экземпляром ActiveSupport :: ModelName, в Rails 3 это ActiveModel :: Name

...