Я знаю, что это старый вопрос. Вот пример, который мне нравится, который включает в себя ответы @flOOr и @Alan_Peabody. (Протестировано в Rails 4.2, возможно, работает в Rails 5)
В вашей модели создайте белый список при запуске. В Dev это должно быть загружено.
class Ad < ActiveRecord::Base
Rails.application.eager_load! if Rails.env.development?
TYPE_NAMES = self.subclasses.map(&:name)
#You can add validation like the answer by @dankohn
end
Теперь мы можем ссылаться на этот белый список в любом контроллере для построения правильной области, а также в коллекции для: type select на форме и т. Д.
class AdsController < ApplicationController
before_action :set_ad, :only => [:show, :compare, :edit, :update, :destroy]
def new
@ad = ad_scope.new
end
def create
@ad = ad_scope.new(ad_params)
#the usual stuff comes next...
end
private
def set_ad
#works as normal but we use our scope to ensure subclass
@ad = ad_scope.find(params[:id])
end
#return the scope of a Ad STI subclass based on params[:type] or default to Ad
def ad_scope
#This could also be done in some kind of syntax that makes it more like a const.
@ad_scope ||= params[:type].try(:in?, Ad::TYPE_NAMES) ? params[:type].constantize : Ad
end
#strong params check works as expected
def ad_params
params.require(:ad).permit({:foo})
end
end
Нам нужно обработать наши формы, потому что маршрутизацию следует отправлять контроллеру базового класса, несмотря на фактический тип объекта. Для этого мы используем «становление», чтобы обмануть построителя форм в правильной маршрутизации, и директиву: as, чтобы входные имена также были базовым классом. Эта комбинация позволяет нам использовать неизмененные маршруты (ресурсы: реклама), а также строгую проверку параметров для параметров [: ad], возвращающихся из формы.
#/views/ads/_form.html.erb
<%= form_for(@ad.becomes(Ad), :as => :ad) do |f| %>