This project is archived and is in readonly mode.
It is no longer possible to use Non-Integer id columns in rails 3
Reported by Kieran McCusker | November 12th, 2010 @ 12:35 PM
Hi
I am only raising this here as I have spent quite a few hours searching for why my 2.3.8 project no longer works in rails 3 and I thought someone else could find this post.
I am using Postgresql and uuids (guids) as the primary key (id) column.
This works fine in 2.3.8 but fails silently in rails 3.0.1. A cursory glance at Activerecord suggests it now insists on integer primary key id's.
e.g. On my box
PUBLISH::Document.first('e06ae583-bea5-474e-8c68-9a9d96caeefd') works fine in 2.3.8
but fails with
TypeError: can't convert String into Integer
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.1/lib/active_record/relation/finder_methods.rb:117:in `first'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.1/lib/active_record/relation/finder_methods.rb:117:in `first'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.1/lib/active_record/base.rb:439:in `__send__'
in rails 3.0.1
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.1/lib/active_record/base.rb:439:in `first'
PUBLISH::Document.create! creates the database record but reports the id as nil in 3.0.1
As this was supported in 2.3, but not in 3.0.1, I think this should be made more explicit in the upgrade guidance.
Many Thanks
Kieran
Comments and changes to this ticket
-
Andrew White November 12th, 2010 @ 01:05 PM
- Importance changed from to Low
PUBLISH::Document.first(n) returns the first n records - you want find(id) instead.
-
Kieran McCusker November 12th, 2010 @ 01:47 PM
Yep, sorry about that, but the central problem still stands that id returns nil and relations do not work e.g.
d = PUBLISH::Document.create!
d.chapters.create!Does not create a document with a chapter belonging to it in the database as it does in 2.3.8
-
Jason Langenauer November 13th, 2010 @ 09:52 PM
I think you need to investigate this a bit further. I've got a Rails 3.0.1 app which also uses non-Integer primary keys (in my case, just a string though), and I'm able to do things like
EventType.find("documents_create")
which works find.
I suspect this may be due to the string to integer coercion which ActiveRecord::Base.find does to allow use to say things like Thing.find(params[:id]), when the integer id in the params hash is actually a string. So this may be a bug specific to GUID/UUID-type identifiers, rather than all non-integer primary keys.
-
Kieran McCusker November 22nd, 2010 @ 06:06 PM
I'm a little further down the line, and have updated to Activerecord 3.0.3
I have a postgresql table with a column {id uuid} as the primary key. To get d = PUBLISH::Document.create! to work I have replaced pk_and_sequence_for in the postgresql activerecord adapter with :-
def pk_and_sequence_for(table) #:nodoc: # Look for a single column primary key # If it is a sequence then return the sequence result = query(<<-end_sql, 'PK and serial sequence')[0] SELECT a.attname, MIN( CASE WHEN d.adsrc ~* '^nextval\\(' THEN CASE WHEN split_part(d.adsrc, '''', 2) ~ '.' THEN substr(split_part(d.adsrc, '''', 2), strpos(split_part(d.adsrc, '''', 2), '.')+1) ELSE split_part(d.adsrc, '''', 2) END ELSE NULL END ) FROM pg_attribute a JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum join pg_constraint c on c.conrelid = a.attrelid and a.attnum = any (c.conkey) WHERE c.contype = 'p' and a.attrelid = '#{quote_table_name(table)}'::regclass AND a.attnum > 0 AND NOT a.attisdropped group by 1 having count(*) = 1 end_sql # [primary_key, sequence] result end
i.e. I will take as my primary key a single column defined as a primary key that also has default. If the default is a sequence I will return that as the sequence. This seems to me to be what the original code is striving for.
As a side point in our production database the old code returned almost 1000 rows in the first select in the old function and was almost an order of magnitude slower.
There are a couple of other changes I needed to the adapter as well
-
In the quote function I needed
elsif value.kind_of?(String) && column.sql_type == 'uuid' "'#{quote_string(value.gsub("'",''))}'"
Otherwise when I do update_attribute I get an extra set of quotes around the uuid which causes the sql to fail.
-
In table_exists? function I needed
exists = query(<<-SQL).first[0].to_i > 0 SELECT COUNT(*) FROM pg_tables WHERE tablename = '#{table.gsub(/(^"|"$)/,'')}' #{schema ? "AND schemaname = '#{schema}'" : ''} SQL if !exists ## Check if it is actually a view exists = query(<<-SQL).first[0].to_i > 0 SELECT COUNT(*) FROM pg_views WHERE viewname = '#{table.gsub(/(^"|"$)/,'')}' #{schema ? "AND schemaname = '#{schema}'" : ''} SQL end exists
as one of our tables is actually a view - Although I suppose I could recode this quite easily
-
-
Kieran McCusker November 23rd, 2010 @ 09:48 AM
Sorry this application goes back to 2006 - We've never implemented migrations
-
Neeraj Singh November 23rd, 2010 @ 09:49 AM
- State changed from new to resolved
-
Kieran McCusker November 23rd, 2010 @ 10:23 AM
Hi
I wonder if you could you say how this has been resolved? My original question was about changes in the way 3.0 Activerecord worked breaking current applications in an undocumented way. Are thinking this is just an application written in 2006? It has been under development ever since and is currently in production under 2.3.8
The changes I made to the postgresql adapter resolve these issues, but I suspect that you are not thinking of looking at or merging them. Have you updated the upgrade guidance with the new requirement that postgresql now can only use serial columns as primary keys?
Many thanks
Kieran
-
Kieran McCusker November 23rd, 2010 @ 10:25 AM
Sorry for posting again, but actually I didn't have any migrations anyway - I was simply trying to get the application working under Rails 3.0
-
Kieran McCusker November 23rd, 2010 @ 12:22 PM
There are loads of tables in the schema. In terms of the problem table the first three columns look like (with primary key shown) :-
CREATE TABLE publishing.documents
( id uuid NOT NULL DEFAULT uuid_generate_v4(), version_no integer DEFAULT 2, created_by integer, PRIMARY KEY (id) )Is this what you wanted?
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>