has_one / belongs_to方法

时间:2016-04-14 19:02:43

标签: ruby-on-rails ruby-on-rails-4

我有一个简单的关系:

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

1 个答案:

答案 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