我目前在我的一个activeadmin页面中有一个嵌套资源的表单:
f.inputs "Courses" do
f.has_many :registrations, :allow_destroy => true, new_record: true do |tc|
tc.input :course
tc.input :semester
end
end
这适用于学生资源。 学生通过注册有很多 course_offerings 。但是,我不希望用户直接从菜单中选择 course_offering (因为每年会有很多重复相同的课程)。而是有课程和学期的输入。 课程和学期是注册模型上的实例变量。它们在表单中设置,然后在后保存挂钩中找到正确的 course_offering 并与注册相关联。代码如下:
def semester=(s)
@semester = s.to_i
end
def semester
self.course_offering.semester
end
def course=(co)
@course = co.to_i
end
def course
self.course_offering.course
end
before_save :set_course_offering
def set_course_offering
self.course_offering = CourseOffering.where(semester_id: @semester, course_id: @course).first
#TODO: Handle case where no course offering is found
end
我有两个问题。第一个是当注册表为空时我得到一个nil指针错误。
nil的未定义方法`course':NilClass
我的学生模型中有accepted_nested_attributes调用。
accepts_nested_attributes_for :registrations, :allow_destroy => true
这是我在查找错误时得到的唯一建议,但尽管有这段代码仍然可以得到它。当我删除课程和学期并将其替换为 course_offering 时,似乎工作正常。
我遇到的下一个问题是,在更新后学生记录没有保存。我认为这是因为当我只更新两个课程和学期实例变量时,我不会对数据库进行任何更改。我要么需要更新另一个输入,要么将调用添加到semester =方法。
答案 0 :(得分:0)
您收到undefined method
错误,因为当注册表为空时,没有与您的学生相关的课程产品,因此在课程的访问者方法中,您nil
获得self.course_offerings
。你可以尝试这个,而不考虑零值:
def course
self.course_offering.try(:course)
end
您不需要accept_nested_attributes_for
,因为您不想通过学生创建或修改课程。
对于你的第二个问题:你对脏跟踪是正确的。您的模型未保存,因为您的学生模型尚未从ActiveRecord的角度进行修改。在保存模型之前,您需要使用course_attribute_will_change!
方法将属性(例如course_offering
)标记为脏。
虽然这种情况看起来是引入表单对象的一个很好的例子。有一个很棒的图书馆叫reform。