参考这篇文章:Rails: Deal with several similar model classes?
结合使用STI和商店功能来组织非常相似的模型。
“使用名为settings的文本列声明Student的基本模型。
class Student < ActiveRecord::Base
store :settings
# name, email, phone, address etc..
end
class HighSchoolStudent < Student
# declare HighSchoolStudent specific attributes
store_accessor :settings, :gpa
end
如何在学生控制器下保留HighSchoolStudent表单?
我不想为HighSchoolStudent添加单独的控制器或路由资源,有没有办法为Student和HighSchoolStudent提供一个表单,并带有一个复选框,指示它是学生还是HighSchoolStudent?我是否只需要为子类创建的额外属性仅在检查特定类时才需要提交表单?
<%= simple_form_for(@student, html: {class: "form-horizontal"}) do |f| %>
<%= f.input :name, as: :text, input_html: {rows: "1"} %>
<%= f.input :email, as: :text, input_html: {rows: "2"} %>
<%= f.input :gpa, as: :text, input_html: {rows: "1"} %>
<%= f.button :submit, class: "btn btn-primary" %>
答案 0 :(得分:2)
当然,您可以创建一个任意复选框,并在创建操作中检查其值:
# In your view
<%= check_box_tag :high_school %>
# In your controller
def create
base_class = params[:high_school] ? HighSchoolStudent : Student
base_class.create(params[:student])
...
end
只有选中了复选框,才能确保特定于HighSchoolStudent
的任何验证。
答案 1 :(得分:2)
Rails STI使用type
特殊列来存储类名。 Student.new(type: 'HighSchoolStudent')
会构建一个Student
,后来会充当HighSchoolStudent
。
此解决方案不会运行仅针对HighSchoolStudent
定义的验证,回调等,但会运行Student
中的所有内容。
要做到这一点,你可以做一些像@PinnyM建议的事情,或者你可以have a hidden input for the type
attribute: hidden_field_tag :type, 'Student'
followed by a check_box_tag :type, 'HighSchoolStudent'
并使用它来确定要创建的正确类,它会为你购买所有的验证和回调,同时更易于维护它使用正确的属性。
所有这一切,STI在这里可能是错误的解决方案。
我是否只需要为子类创建的额外属性仅在检查特定类时才需要提交表单?
这告诉我你已经在你的students
表中添加了与非HighSchool学生无关的属性。
更好的解决方案可能是让HighSchoolStudentProfile
类作为关联,并在学生上检查其存在的方法high_schooler?
。这可以防止你遇到我以前遇到的问题,这个问题有一个“稀疏表”,并且通常会变成需要各种条件验证并且具有复杂的逻辑。