When using a legacy database or when writing to a view, if a column is set to auto-increment, but the schema doesn't define it as a "primary key", then active record fails to properly set the primary_key column in the schema_cache early enough.
It looks like by calling #create, the schema_cache's colums are filled before AR:Base#columns gets called. #columns being the method that sets the primary_key in the cache
I've included a failing test as well as a proposed fix in this gist.
In my opinion #columns is probably not the place to be putting the primary_key in the cache though since clearly the column definitions in the cache are filled before #columns is called. A better fix would be to either 1. find a better time earlier in the query life cycle to cache the primary_key as set by AR, or 2. cache the column definitions later in the query cycle.
FYI: This issue was caused by this patch's attempt to fix this issue
Just curious. Why didn't you remove the similar code from #columns?
Because that would bring back bug #2807.
How so? Doesn't the if connected? fix that?
-- $ git diff
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 9215a68..511292a 100644
@@ -767,10 +767,6 @@ module ActiveRecord #:nodoc:
# Returns an array of column objects for the table associated with this class.
- if defined?(@primary_key)
- connection.schema_cache.primary_keys[table_name] ||= primary_key
-- $ ruby -Itest test/cases/primary_keys_test.rb -n test_set_primary_key_with_no_connection
Using sqlite3 with Identity Map off
Loaded suite test/cases/primary_keys_test
Finished in 0.006121 seconds.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 36004 --name "test_set_primary_key_with_no_connection"
Yes but now when you call Model.columns none of the items will have primary == true. The test doesn't show this though.
Okay, if thats true, then this current issue will still exist if the Model is loaded when the db is not connected, then the db connects, then queries are run.
that's what the if defined?(@primary_key) ... in columns is for - in case you set the primary key before a connection existed. that's why we can't delete it.
if defined?(@primary_key) ...
Yes, but that means this bug, bug 3987 isn't fixed. I'll write up a new script to prove it to you.
Your changes this morning on master fixes this bug there. However 3-1-stable still fails with this new test:
## must run activerecord's `rake postgresql:build_databases`
ActiveRecord::Base.establish_connection(:adapter => 'postgresql', :database => 'activerecord_unittest')
CREATE SEQUENCE foo_seq;
CREATE TABLE posts(
foo int NOT NULL DEFAULT nextval( 'foo_seq'::regclass )
connection = ActiveRecord::Base.remove_connection
class Post < ActiveRecord::Base
DROP TABLE posts;
DROP SEQUENCE foo_seq;