2017-01-01 3 views
6

Нужна помощь в понимании этого кода, насколько мне известно. «< <» добавить в коллекцию, но здесь она сохраняет запись правильно, как это происходит без вызова .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 

ответ

6

Возможно, поиск исходного кода поможет вам. Это мой след поисков на основе метода << в activerecord:

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

rails/collection_proxy.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 

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

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_association.rb#L32

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 

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

Как вы можете видеть, в конце концов, это делает вызов метода save.

Отказ от ответственности: Я не знаком с кодом Rails, но у вас есть интересный вопрос.

6

В has_manydocumentation он говорит:

Добавляет один или несколько объектов в коллекции, установив их иностранных ключи к первичному ключу коллекции. Обратите внимание, что эта операция мгновенно запускает обновление SQL без ожидания сохранения или обновления. вызовите родительский объект, если родительский объект не является новой записью.

2

В отношении has_many информация о связи сохраняется в целевой записи. Это означает, что << должен будет изменить эту запись, чтобы добавить ее в набор.

Возможно, намереваясь удобство, ActiveRecord автоматически сохраняет их для вас при выполнении задания, если задание было успешным. Исключение составляет для новых записей, запись, с которой они связаны, не имеет идентификатора, поэтому его нужно отложить. Они сохраняются, когда запись, с которой они связаны, наконец создается.

Это может быть немного запутанным, возможно, неожиданным, но на самом деле это то, что вы хотели бы совершить в 99% случаев. Если вы не хотите, чтобы это произошло, вы должны манипулировать связь вручную:

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

Это в основном эквивалентны, но намного более многословным.