rails: has_many :through **validate=>false** not being obeyed during association update

Steps to reproduce

Bug report script attached

Expected behavior

As per docs, when setting the option has_many :validate => false, the associated objects will not be validated when saving the object.

4.1.2.11 :validate

If you set the :validate option to true, then associated objects will be validated whenever you save this object. By default, this is false: associated objects will not be validated when this object is saved.

Actual behavior

When updating the association, using #role_ids=, the associated object is being validated.

System configuration

Rails version: 5.0.0

Ruby version: 2.3.1

https://gist.github.com/marcalc/a370674c040bd2122da729b904557c08#file-bug-report-rb


begin
  require 'bundler/inline'
rescue LoadError => e
  $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
  raise e
end

gemfile(true) do
  source 'https://rubygems.org'
  # Activate the gem you are reporting the issue against.
  gem 'activerecord', '5.0.0'
  gem 'sqlite3'
end

require 'active_record'
require 'minitest/autorun'
require 'logger'

# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table "roles", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "user_roles", force: :cascade do |t|
    t.integer  "user_id"
    t.integer  "role_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["role_id"], name: "index_user_roles_on_role_id"
    t.index ["user_id"], name: "index_user_roles_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end

class Role < ActiveRecord::Base
  validates_presence_of :name
end

class User < ActiveRecord::Base
  has_many :user_roles
  has_many :roles, through: :user_roles, validate: false
end

class UserRole < ActiveRecord::Base
  belongs_to :user
  belongs_to :role
end

class BugTest < Minitest::Test
  def test_association_stuff
    Role.new(name: nil).save(validate: false) # deliberately creating an invalid nameless role

    u = User.create!(role_ids: ["1"]) # OK
    u.update!(role_ids: nil) # OK
    u.update!(role_ids: ["1"]) # FAILS
  end
end

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 6
  • Comments: 16 (3 by maintainers)

Commits related to this issue

Most upvoted comments

Looking through the issue history I see this issue mentioned many times by many people, going back years, #25752, #21058, #21077, #36563.

A few times a pull request was attempted but in the end people stop commenting and Rails Bot closes the ticket. Apparently there’s no satisfactory way to solve this issue?

We’re having the same problem and I think it should be fixed as a regression.

Any news on this? We’re running into this as well and the fix seems to work fine.

I have the same problem on habtm association. When I’m trying to add more associations it validates them and fails. Rails 4.2.8 works perfect. I have no idea why it validates existing records when adding to habtm association. But what is even more unclear is why it fails with exception rather than throwing validation error?

That’s a bug for sure. At least it doesn’t follow convention. You call save and it saves associated things Also, so if you pass validate: false, it should apply the same rule to whole tree. Otherwise it doesn’t make sense to save whole tree, but disable validation just for the root object

Just got bitten by this as well. @dhh thoughts ? Tis pull has been opened for a while

Currently bitten by this using 5.1. Did anyone come up with a good workaround? The best thing I can come up with currently is just doing the insert in raw SQL.

As nobody have given any feedback, I just created a pull request demonstrating the necessary change in order to fix the intended behavior. Please comment if you believe this is wrong or I made the wrong assumption about the mentioned problem.

#25752

@rafaelfranca Would you mind to help me on this? Sorry to pull you on this.

I’m a little confused too, @mrgilman. But thanks!

I just checked this behavior on activerecord-3.2.22 and 4.2.6 and in fact it worked like I’ve been expecting. Unless there has been a deliberate change in this behavior, I’m inclined to think that this could be a regression.

Here is a gist of the same bug report using activerecord-3.2.22.

https://gist.github.com/marcalc/cc2f5b018498e6c44e12df0523dc3b9d

Thanks! =)