activerecord-import: Presence validation not causing import to fail

Relevant code:

results = Flashcard.import cards_for_import, timestamps: false, on_duplicate_key_update: {
      conflict_target: %i[client_id user_id], columns: %i[created_at updated_at keyword_text
                                                          keyword_meaning example_usage keyword_locale
                                                          front_note back_note]
}

The model has a keyword_text cannot be blank presence validation: validates :user, :keyword_text, :client_id, :keyword_locale, :keyword_meaning, presence: true

So, I have an array of objects to import that looks like this (some fields omitted, important part is that keyword_text is blank):

p cards_for_import
[#<Flashcard id: 1, user_id: 1,  keyword_text: "", keyword_meaning: "tabgo tego qui tepesco autem", 
example_usage: "Magnam qui magni. Debitis ut distinctio. Aut dolor...", created_at: "2018-11-26 02:21:58", 
updated_at: "2018-11-26 02:21:58", deleted_at: nil, client_id: 1543199098550>]

Problem is, calling cards_for_import.first.valid? returns false, but if I import the record as is, results returns:

#<struct ActiveRecord::Import::Result failed_instances=[], num_inserts=1, ids=[1], results=[]>

The card is then added to the database even though it actually violates a model’s presence constraint, confirmed with valid? being false. I manually tried turning validate: true on, but no luck.

Is this intentional behavior?

My understanding is that it should be stored in failed_instances, not added regardless.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 23

Most upvoted comments

Not the prettiest solution but it works:

class User < ApplicationRecord
  has_one :profile
  validates_presence_of :profile
  validate :validate_associations, on: :import

  private

  def validate_associations
    errors.add(:profile, :blank) if profile.blank?
  end
end

users = [...]

ActiveRecord::Associations::Preloader.new.preload users, [:profile]

User.import users, validate_with_context: :import

@timfsw that is a different issue I believe. See: #518

We purposely prevented validating belongs_to associations because it was executing a sql query for every record imported to make sure the association exists in the database. This came about because Rails 5 validates presence of belongs_to associations by default now. I’m not exactly sure how to proceed with that one, I’ll need to think on it. Any input from others is appreciated.

In my opinion, this should be an importer validation option with a disclaimer about slower performance. Having the behavior of ActiveRecord validations with presence: true differ from activerecord-import’s validate behavior is surprising.

Awesome, thanks Rob!

I actually just released 1.0 which fixed another possible issue with validations. Hopefully we’re good now 🙏

Went ahead and released v0.28.0 with this fix included.