我有一个简单的关系:
Student
has_one :locker, inverse_of: :student, validate: true, dependent: :nullify
accepts_nested_attributes_for :locker
Locker
belongs_to :student, inverse_of: :locker, touch: true
我有一张表格:
<%= f.simple_fields_for :locker do |l| %>
<%= l.input :id, as: :select,
collection: @lockers_collection,
label: false,
value_method: :id,
label_method: :number,
include_blank: true,
input_html: { class: "admin-select2" },
selected: "#{@student.locker ? @student.locker.id : ""}",
wrapper: 'admin_vertical_select' -%>
<% end -%>
当我创建新学生时,我可以分配一个储物柜(或不是),一切都很简单,并按预期工作。好吧,我不得不把这个hackery添加到Student模型中,否则Rails抱怨没有找到记录(这里的解决方案在SO上):
def locker_attributes=(attributes)
if attributes['id'].present?
self.locker = Locker.find(attributes['id'])
end
super
end
无论如何,我遇到的主要问题是编辑/更新操作。 首先,我需要检查学生目前是否有一个储物柜来建立新的或现有的:
if @student.locker
@student.build_locker(id: @student.locker.id)
else
@student.build_locker
end
现在我正试图寻找解决方案的真正问题。 基本上几乎没有可能发生的情况:
学生有一个储物柜,但我想清除它
在这两种情况下,学生不会更新,因为(我怀疑)Locker是空的。如何处理?
然后还有可能将Locker从一个更改为另一个。 在这种情况下,我不知何故认为Rails将足够聪明地更新“旧”Locker。我可以看到旧储物柜上的student_id id是零,但是Rails是如何做到的?问题是我在Locker上有一个paper_trail,当它变空时我需要对旧版本进行版本控制。
如何处理空场景?这是我最大的问题。 我做得对吗还是有更好的方法吗?
THX
答案 0 :(得分:0)
如果您将inverse_of
添加到模型中的关联中,例如:
has_one :locker, inverse_of: :student
belongs_to :student, inverse_of: :locker
你只能使用:
@student.build_locker unless @student.locker
你不需要def locker_attributes=(attributes)
方法。
要使锁定器无效,您可以将以下内容添加到某个控制器中的操作,如下所示:
@student.locker = nil
@student.save