Rails 4: разница между проверкой наличия на id или ассоциацией

Если у меня есть ассоциация 'belongs_to' в модели, я хотел бы знать условную разницу между проверкой ассоциации:

  class Topping  < ActiveRecord::Base
    belongs_to :pancake
    validates  :pancake, presence: true
    ...

и проверки соответствующего идентификатора модели:

  class Topping  < ActiveRecord::Base
    belongs_to :pancake
    validates  :pancake_id, presence: true
    ...

Мотивация:

Некоторый код, который присвоил долину блину, в какой-то момент переставал работать. Изменение валидации от ассоциации с идентификатором "исправлено" проблема, но я хотел бы узнать более глубокую причину.

(FYI, когда вы входите в код, блин был действительным, а в базе данных и topping отвечали как на .pancake, так и на .pancake_id соответственно. Оператор push (pancake.toppings << topping) и ручное назначение и сохранение (topping.pancake = pancake; topping.save) не удалось с ошибкой проверки блина.)

Ответ 1

Изучая далее, я обнаружил, что валидатор "присутствия" разрешает "add_on_blank":

http://apidock.com/rails/ActiveModel/Errors/add_on_blank

def add_on_blank(attributes, options = {})
  Array(attributes).each do |attribute|
    value = @base.send(:read_attribute_for_validation, attribute)
    add(attribute, :blank, options) if value.blank?
  end
end

Это делает то, что он говорит: добавляет ошибку проверки, если это свойство blank?

Это означает, что это просто проверка существования. Поэтому, если я проверяю идентификатор, этот идентификатор должен существовать. Это означает:

topping.pancake = Pancake.new
topping.valid?

вернет false. Однако:

topping.pancake_id = -12
topping.valid?

вернет true. С другой стороны, если я проверяю объект, то полная противоположность будет истинна. Если -12 - действительный индекс, в этом случае ActiveRecord автоматически загрузит его из базы данных при получении сообщения "блин".

Перейдя к моей проблеме, дальнейшее расследование показало, что blank? делегирует empty?, и действительно кто-то определил empty? на блине, вернув true, если нет начинок.

Обнаружен преступник, и кое-что о Rails узнали.