回答第一个问题
一种解决方案是您可以将:user
and标记:course
为只读。
attr_readonly :user_id, :course_id
这样就可以在创建时设置它们,但不能在更新时设置它们。如果您希望它们将来可以更新,您可以在注册模型上创建一个特殊的方法,@registration.update_dangerous_stuff(params)
并且只在具有更高权限的用户可以访问的控制器操作中使用此方法。该方法将使用类似的东西update_column
来改变这些字段。
另一种方法是创建用于设置用户和课程的虚拟属性,这些属性具有决定是否可以设置用户或课程的逻辑。这是一个例子。
attr_accessor :safe_user, :safe_course
attr_accessible :safe_user, :safe_course
before_save :set_user, if: 'user.blank?'
before_save :set_course, if: 'course.blank?'
def set_user
self.user = safe_user
end
def set_course
self.course = safe_course
end
因此,在您将使用safe_user
andsafe_course
字段而不是user
and的表单中course
。在这种情况下,它只会设置实际的user
并且course
如果它们是空白的,并且它们实际上从未公开为可访问的。您可以通过使用回调条件来绕过此规则。
回答第二个问题
当您以复杂的形式提交一堆数据时,您需要想出一种方法来判断这些数据中哪些是有意义的,哪些只是一个占位符。如果没有提交有意义的数据,就不要创建注册。您必须决定哪些表单字段“足以”看到有人实际上尝试填写它们并犯了错误,而不是有人甚至从未接触过嵌套表单的情况。如果没有简单的方法来确定 - 一种方法是在嵌套表单中添加一个复选框“添加此注册”。如果选中该复选框 - 将尝试创建并运行验证。之后,您可以添加一些 javascript 来隐藏此复选框,并在有人激活嵌套表单中的任何字段时自动检查它。
为了在后端促进这种行为,你有accepts_nested_attributes_for
rails 方法。例如,您可以在课程模型中说如下内容。
accepts_nested_attributes_for :registrations,
reject_if: -> attrs { attrs[:name].blank? }
# Don't forget this too
attr_accessible :registrations_attributes
Rails 还提供了一个快捷方式。
accepts_nested_attributes_for :registrations, reject_if: :all_blank
在复选框的情况下,您可以说reject_if: -> attrs { attrs[:my_check_box] == '1' }
,等等。
告诉railsreject_if
如果不满足给定过程中的条件,它将简单地忽略注册,而不是尝试创建和验证它。
希望这能给你一些想法。