Created
February 25, 2025 03:45
Rails `after_create` <> `has_many through` weirdness
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "bundler/inline" | |
gemfile(true) do | |
source "https://rubygems.org" | |
gem "rails" | |
# If you want to test against edge Rails replace the previous line with this: | |
# gem "rails", github: "rails/rails", branch: "main" | |
gem "sqlite3" | |
end | |
require "active_record/railtie" | |
require "minitest/autorun" | |
# This connection will do for database-independent bug reports. | |
ENV["DATABASE_URL"] = "sqlite3::memory:" | |
class TestApp < Rails::Application | |
config.load_defaults Rails::VERSION::STRING.to_f | |
config.eager_load = false | |
config.logger = Logger.new($stdout) | |
config.secret_key_base = "secret_key_base" | |
config.active_record.encryption.primary_key = "primary_key" | |
config.active_record.encryption.deterministic_key = "deterministic_key" | |
config.active_record.encryption.key_derivation_salt = "key_derivation_salt" | |
end | |
Rails.application.initialize! | |
ActiveRecord::Schema.define do | |
create_table :users do |t| | |
t.text :name | |
end | |
create_table :roles do |t| | |
t.text :title | |
end | |
create_table :user_roles do |t| | |
t.belongs_to :user | |
t.belongs_to :role | |
t.index [:user_id, :role_id], unique: true | |
end | |
end | |
class User < ActiveRecord::Base | |
# placing assign_default_role here causes unique constraint errors | |
after_create :assign_default_role | |
has_many :user_roles | |
has_many :roles, through: :user_roles | |
# placing assign_default_role here works for unknown-to-me reasons | |
# after_create :assign_default_role | |
def assign_default_role | |
role = Role.first | |
roles << role | |
end | |
end | |
class Role < ActiveRecord::Base | |
has_many :user_roles | |
has_many :users, through: :user_roles | |
end | |
class UserRole < ActiveRecord::Base | |
belongs_to :user | |
belongs_to :role | |
end | |
class BugTest < ActiveSupport::TestCase | |
def test_association_stuff | |
role = Role.create!(title: "admin") | |
user = User.create!(name: "Derpman") | |
assert_equal 1, user.roles.count | |
assert_equal user.id, role.users.first.id | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Issue described in this forum post
https://discuss.rubyonrails.org/t/order-of-after-create-callback-and-has-many-through-causes-a-database-constraint-violation/88719