1

参考这篇文章:Rails:处理几个类似的模型类?

使用 STI 和 Store 特征的组合来组织非常相似的模型。

“使用名为设置的文本列为 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 创建表单,同时保留在 Student 控制器下?

我不想为 HighSchoolStudent 添加单独的控制器或路由资源,有没有办法为 Student 和 HighSchoolStudent 提供一个表格,并带有一个复选框来指示它是 Student 还是 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" %>
4

2 回答 2

2

Rails STI 使用type特殊列来存储类名。Student.new(type: 'HighSchoolStudent')将构建一个Student稍后将充当HighSchoolStudent.

HighSchoolStudent该解决方案不会运行仅为Student.

为此,您可以执行@PinnyM 建议的操作,或者您可以为该type属性设置一个隐藏的输入:hidden_field_tag :type, 'Student'后跟 acheck_box_tag :type, 'HighSchoolStudent'并使用它来确定要创建的正确类,这确实为您购买了所有的验证和回调。更易于维护,因为它使用了正确的属性。


话虽如此,STI 在这里可能是您的错误解决方案。

我是否可以只要求为子类创建的额外属性仅在选中该特定类的情况下才需要提交表单?

这告诉我,您已在students表格中添加了与非高中生无关的属性。

一个更好的解决方案可能是有一个像HighSchoolStudentProfile关联这样的类和一个high_schooler?检查学生是否存在的方法。这可以防止您遇到我之前遇到的问题,即具有“稀疏表”并且通常会发展为需要各种条件验证并且具有复杂的逻辑。

于 2013-09-03T19:00:24.563 回答
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只有在检查复选框时,才能确保任何特定的验证。

于 2013-09-03T17:48:55.800 回答