Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec, Rails 4, Postgres, UUID primary keys: id is null with Rake + RSpec, but is fine in RSpec or console

I'm trying to get up and running with UUID primary keys for a model with Postgres and Rails 4.0.0.rc2, but my specs are failing to create and destroy, yet MyThing.create or MyThing#destroy works fine from the rails console (in both dev and test environments). ...until I run specs, in which case doing either of those things stops working via the console. Thus, it looks like something that happens when I run my specs that alters my DB and prohibits UUID keys from continuing to work.

Halp?

I followed this blog post to generate my migration, thus my schema looks like:

ActiveRecord::Schema.define(version: 20130613174601) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"
  enable_extension "uuid-ossp"

  create_table "growers", id: false, force: true do |t|
    t.uuid     "id",         null: false
    t.string   "name"
    t.string   "code"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end

Here's the progression of things:

Create: $ rake db:create RAILS_ENV=test

Migrate:

$ rake db:migrate RAILS_ENV=test
==  CreateGrowers: migrating ==================================================
-- enable_extension("uuid-ossp")
   -> 0.0052s
-- create_table(:growers, {:id=>:uuid})
   -> 0.0043s
==  CreateGrowers: migrated (0.0096s) =========================================

Create model object:

$ rails c test
agrian> g = Grower.create name: 'bobo'
   (0.3ms)  BEGIN
  SQL (4.1ms)  INSERT INTO "growers" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", Tue, 18 Jun 2013 20:22:39 UTC +00:00], ["name", "bobo"], ["updated_at", Tue, 18 Jun 2013 20:22:39 UTC +00:00]]
   (0.4ms)  COMMIT
=> #<Grower id: "38f84f39-e52e-4664-b776-4fdfcbd60b09", name: "bobo", code: nil, created_at: "2013-06-18 20:22:39", updated_at: "2013-06-18 20:22:39">

(rejoicing)

Run specs:

$ rake spec
/Users/sloveless/.rbenv/versions/2.0.0-p195/bin/ruby -S rspec ./spec/controllers/api/v1/growers_controller_spec.rb ./spec/helpers/growers_helper_spec.rb ./spec/models/grower_spec.rb ./spec/requests/api/v1/growers_spec.rb ./spec/routing/api/v1/growers_routing_spec.rb
...............FF..........F.*
(other stuff)
Finished in 0.30626 seconds
30 examples, 3 failures, 1 pending

Create model object:

$ rails c test
Loading test environment (Rails 4.0.0.rc2)
agrian> g = Grower.create name: 'bobo'
   (0.4ms)  BEGIN
  SQL (3.5ms)  INSERT INTO "growers" ("created_at", "name", "updated_at") VALUES ($1, $2, $3)  [["created_at", Tue, 18 Jun 2013 20:29:36 UTC +00:00], ["name", "bobo"], ["updated_at", Tue, 18 Jun 2013 20:29:36 UTC +00:00]]
PG::Error: ERROR:  null value in column "id" violates not-null constraint
DETAIL:  Failing row contains (null, bobo, null, 2013-06-18 20:29:36.773391, 2013-06-18 20:29:36.773391).
: INSERT INTO "growers" ("created_at", "name", "updated_at") VALUES ($1, $2, $3)
   (0.2ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::Error: ERROR:  null value in column "id" violates not-null constraint
DETAIL:  Failing row contains (null, bobo, null, 2013-06-18 20:29:36.773391, 2013-06-18 20:29:36.773391).
: INSERT INTO "growers" ("created_at", "name", "updated_at") VALUES ($1, $2, $3)
from /Users/sloveless/.rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0.rc2/lib/active_record/connection_adapters/postgresql_adapter.rb:780:in `get_last_result'

(sad face)

Can someone point me in the right direction here as to what might be doing silly stuff with my db?

Update: I can run bin/rspec spec over and over again with success (all my specs pass). If I run rake spec, I get failures, then the next time I run bin/rspec spec I get failures.

Edit: Updated title to reflect rake + rspec problem, not just with rspec.

like image 526
turboladen Avatar asked Jun 18 '13 20:06

turboladen


2 Answers

I see that rspec-rails/lib/rspec/rails/tasks/rspec.rake defines this for the spec task:

spec_prereq = Rails.configuration.generators.options[:rails][:orm] == :active_record ?  "test:prepare" : :noop
task :noop do; end
task :default => :spec

# other stuff

desc "Run all specs in spec directory (excluding plugin specs)"
RSpec::Core::RakeTask.new(:spec => spec_prereq)

...which runs:

  • db:load_config
  • db:test:purge
  • db:test:load
  • db:test:load_schema
  • db:schema:load

I see that, when running rake db:schema:load, I get:

-- enable_extension("plpgsql")
   -> 0.0161s
-- enable_extension("uuid-ossp")
   -> 0.0063s
-- create_table("growers", {:id=>false, :force=>true})
   -> 0.0049s
-- initialize_schema_migrations_table()
   -> 0.0062s

...which is different than when I run the migration:

==  CreateGrowers: migrating ==================================================
-- enable_extension("uuid-ossp")
   -> 0.0050s
-- create_table(:growers, {:id=>:uuid})
   -> 0.0052s
==  CreateGrowers: migrated (0.0103s) =========================================

Thus, it seems to me that the db:schema:load task isn't creating the table with the UUID primary key, thus causing the failures. Seems like a Rails bug??

Update: I guess I'll find out if it's a Rails bug: Issue 11016

like image 158
turboladen Avatar answered Nov 15 '22 07:11

turboladen


For others running into something similar:

# config/application.rb
config.active_record.schema_format :sql

In order to get postgres' uuid_ossp extension working, I needed to switch to an sql schema from schema.rb. It seems schema.rb tries to be more database neutral, which understandably results in some wonkiness with custom db extensions.

See vikks comment

like image 2
willscripted Avatar answered Nov 15 '22 09:11

willscripted