rails - left shift"<<&#;操作员自动保存记录

时间:2017-01-01 09:51:05

标签: ruby-on-rails ruby

需要帮助理解这段代码,据我所知,我知道"<<"附加到集合但是这里它正确地保存了记录,如果没有调用.save方法怎么办呢?

#user.rb
 has_many :saved_properties, through: :property_saves, source: :property

#users_controller.rb
def update
  if @user.saved_properties << Property.find(params[:saved_property_id])
        render plain: "Property saved"
end

3 个答案:

答案 0 :(得分:7)

has_many documentation中说:

  

通过设置外部对象,将一个或多个对象添加到集合中   集合主键的键。注意这个操作   立即触发更新SQL而无需等待保存或更新   调用父对象,除非父对象是新记录。

答案 1 :(得分:7)

也许查看源代码会对你有所帮助。这是我基于function navigate(e) { var grid = e.sender; grid.select(grid.tbody.find(e.element.parent())); } 中的<<方法的搜索记录:

activerecord

rails/collection_proxy.rb at 5053d5251fb8c03e666f1f8b765464ec33e3066e · rails/rails · GitHub

def <<(*records)
  proxy_association.concat(records) && self
end

rails/collection_association.rb at 5053d5251fb8c03e666f1f8b765464ec33e3066e · rails/rails · GitHub

def concat(*records)
  records = records.flatten
  if owner.new_record?
    load_target
    concat_records(records)
  else
    transaction { concat_records(records) }
  end
end

rails/collection_association.rb at 5053d5251fb8c03e666f1f8b765464ec33e3066e · rails/rails · GitHub

def concat_records(records, should_raise = false)
  result = true

  records.each do |record|
    raise_on_type_mismatch!(record)
    add_to_target(record) do |rec|
      result &&= insert_record(rec, true, should_raise) unless owner.new_record?
    end
  end

  result && records
end

https://github.com/rails/rails/blob/5053d5251fb8c03e666f1f8b765464ec33e3066e/activerecord/lib/active_record/associations/has_many_association.rb#L32

  def insert_record(record, validate = true, raise = false)
    set_owner_attributes(record)
    set_inverse_instance(record)

    if raise
      record.save!(validate: validate)
    else
      record.save(validate: validate)
    end
  end

https://github.com/rails/rails/blob/5053d5251fb8c03e666f1f8b765464ec33e3066e/activerecord/lib/active_record/associations/has_many_through_association.rb#L38

正如您所看到的,最终它会调用 def insert_record(record, validate = true, raise = false) ensure_not_nested if record.new_record? || record.has_changes_to_save? if raise record.save!(validate: validate) else return unless record.save(validate: validate) end end save_through_record(record) record end 方法。

免责声明:我对Rails的源代码并不熟悉,但你有一个有趣的问题。

答案 2 :(得分:2)

has_many关系中,链接信息保存在目标记录中。这意味着<<必须修改该记录才能将其添加到集合中。

如果作业很方便,ActiveRecord会在作业完成时自动为您保存这些内容。例外情况是新记录,它们所关联的记录没有任何标识符,因此必须延迟。当最终创建与它们关联的记录时,它们将被保存。

这可能有点令人困惑,也许是意料之外的,但它实际上是99%的时间你想要发生的事情。如果您不希望这种情况发生,您应该手动操作链接:

 property = Property.find(params[:saved_property_id])
 property.user = @user
 property.save!

这基本上相当,但更冗长。