Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uniqueness validations pg non-null error for wrong column #600

Closed
stephen-puiszis opened this issue Oct 17, 2014 · 13 comments
Closed

Uniqueness validations pg non-null error for wrong column #600

stephen-puiszis opened this issue Oct 17, 2014 · 13 comments

Comments

@stephen-puiszis
Copy link

Cannot figure out what's going on. The test is failing on the uid uniquness matcher, but for a non-null violation on the first_name column, even though the first-name column matcher is passing. uid is an optional db column for if a user signs-up via omniauth like facebook or linkedin login. I'm creating valid objects prior to running the tests using FactoryGirl and have tried explicitly setting the column values before running the tests. I've dropped all the tables, re-migrated and still have issues. I've changed syntaxes, used expect vs. should and am out of ideas of what is causing this test to fail. Below is reference of the other places I've tried solutions from. Rails version 4.0.5, rspec with shoulda in the test group.

Failure/Error: it { should validate_uniqueness_of(:uid).allow_nil }
     ActiveRecord::StatementInvalid:
       PG::NotNullViolation: ERROR:  null value in column "first_name" violates not-null constraint
       DETAIL:  Failing row contains (110, , , null, null, null, 0, null, null, null, null, 8b1502d6d14a267788d9c06c0412428a4be235f8c4b5b01c8a0d14a1790ff0d3, null, 2014-10-17 04:40:19.569064, null, 2014-10-17 04:40:19.373726, 2014-10-17 04:40:19.373726, null, null, null, null, a).
       : INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "created_at", "uid", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
#spec/models/user_spec.rb
require "spec_helper"

describe User do
  let(:user) { create :user}

  it { should have_db_column(:first_name).of_type(:string).with_options(null: false) }
  it { should have_db_column(:last_name).of_type(:string).with_options(null: false) }
  it { should have_db_column(:phone_number).of_type(:string) }

  it { should have_one(:professional_profile).dependent(:destroy) }

  it { should respond_to(:first_name) }
  it { should respond_to(:last_name) }
  it { should respond_to(:phone_number) }

  describe 'validations' do
    subject { build(:user, first_name: "Hello") }
    it { should validate_presence_of(:first_name) }
    it { should validate_presence_of(:last_name) }
    it { should validate_uniqueness_of(:uid).allow_nil }
  end
...

#models/user.rb
class User < ActiveRecord::Base
rolify
...
  devise :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable,
         omniauth_providers: [:linkedin]

  validates :first_name, presence: true
  validates :last_name,  presence: true
  validates :uid,        uniqueness: true, allow_nil: true
...
@mcmire
Copy link
Collaborator

mcmire commented Oct 17, 2014

What's your :user factory look like?

@stephen-puiszis
Copy link
Author

hey @mcmire, here is our user factory:

FactoryGirl.define do
  factory :user do
    first_name     { Faker::Name.first_name }
    last_name      { Faker::Name.last_name }
    email          { Faker::Internet.email }
    password       { Faker::Lorem.characters(20) }
    sign_in_count  0

    after(:build) {|user| user.confirm! }

    factory :unconfirmed_user do
      after(:build) do |user|
        user.update(confirmed_at: nil)
        user.update(confirmation_token: Faker::Lorem.characters(20))
      end
    end

    factory :admin do
      after(:build) {|user| user.add_role :admin }
    end

    factory :profile_manger do
      after(:build) {|user| user.add_role :profile_manager }
    end

    factory :profile_viewer do
      after(:build) {|user| user.add_role :profile_viewer }
    end
  end
end

@mcmire
Copy link
Collaborator

mcmire commented Oct 17, 2014

@stephen-puiszis Okay and I assume you're using the latest version? I notice you're building the user in your validation tests. Prior to 2.7.0 you had to create the user instead, but a fix went in that made it you wouldn't get the sort of error you got.

If you are using 2.7.0 can you provide a backtrace?

@stephen-puiszis
Copy link
Author

@mcmire We were using 2.5. However, I just updated to 2.7 and am still receiving the same errors. The valiadation specs that I posted was the most recent solution I tried. This is how I was running the user_spec prior to running into this issue. Full backtrace further down.

#user_spec.rb
require "spec_helper"

describe User do
  let(:user) { create :user }

  it { should have_db_column(:first_name).of_type(:string).with_options(null: false) }
  it { should have_db_column(:last_name).of_type(:string).with_options(null: false) }
  it { should have_db_column(:phone_number).of_type(:string) }

  it { should have_one(:professional_profile).dependent(:destroy) }

  it { should respond_to(:first_name) }
  it { should respond_to(:last_name) }
  it { should respond_to(:phone_number) }

  it { should validate_presence_of(:first_name) }
  it { should validate_presence_of(:last_name) }
  it { should validate_uniqueness_of(:uid).allow_nil }
...

Backtrace below:

User
  should require case sensitive unique value for uid (FAILED - 1)

Failures:

  1) User should require case sensitive unique value for uid
     Failure/Error: it { should validate_uniqueness_of(:uid).allow_nil }
     ActiveRecord::StatementInvalid:
       PG::NotNullViolation: ERROR:  null value in column "first_name" violates not-null constraint
       DETAIL:  Failing row contains (635, , , null, null, null, 0, null, null, null, null, 038ed99375ea0ec9dda6375583af089a851c4319412b801a081a032092a88f82, null, 2014-10-17 17:49:35.46899, null, 2014-10-17 17:49:35.263298, 2014-10-17 17:49:35.263298, null, null, null, null, a).
       : INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "created_at", "uid", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/postgresql_adapter.rb:803:in `get_last_result'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/postgresql_adapter.rb:803:in `exec_cache'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/postgresql/database_statements.rb:139:in `block in exec_query'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract_adapter.rb:442:in `block in log'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activesupport-4.0.5/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract_adapter.rb:437:in `log'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_query'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/postgresql/database_statements.rb:184:in `exec_insert'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract/database_statements.rb:107:in `insert'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `insert'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/relation.rb:76:in `insert'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/persistence.rb:510:in `create_record'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/attribute_methods/dirty.rb:78:in `create_record'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/callbacks.rb:306:in `block in create_record'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activesupport-4.0.5/lib/active_support/callbacks.rb:383:in `_run__3117067022564426931__create__callbacks'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activesupport-4.0.5/lib/active_support/callbacks.rb:80:in `run_callbacks'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/callbacks.rb:306:in `create_record'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/timestamp.rb:57:in `create_record'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/persistence.rb:478:in `create_or_update'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/callbacks.rb:302:in `block in create_or_update'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activesupport-4.0.5/lib/active_support/callbacks.rb:383:in `_run__3117067022564426931__save__callbacks'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activesupport-4.0.5/lib/active_support/callbacks.rb:80:in `run_callbacks'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/callbacks.rb:302:in `create_or_update'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/persistence.rb:103:in `save'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/validations.rb:51:in `save'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/attribute_methods/dirty.rb:32:in `save'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:270:in `block (2 levels) in save'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:330:in `block in with_transaction_returning_status'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract/database_statements.rb:221:in `within_new_transaction'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:209:in `transaction'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:327:in `with_transaction_returning_status'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:270:in `block in save'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:285:in `rollback_active_record_state!'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/activerecord-4.0.5/lib/active_record/transactions.rb:269:in `save'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:264:in `block in create_record_in_database'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:261:in `tap'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:261:in `create_record_in_database'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:241:in `first_instance'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:237:in `existing_record'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:366:in `existing_value'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:297:in `validate_everything_except_duplicate_nils?'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:220:in `matches?'
     # /Users/stephenpuiszis/.rvm/gems/ruby-2.1.1@global/gems/rspec-expectations-2.14.4/lib/rspec/expectations/handler.rb:24:in `handle_matcher'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/memoized_helpers.rb:68:in `should'
     # ./spec/models/user_spec.rb:18:in `block (2 levels) in <top (required)>'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:114:in `instance_eval'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:114:in `block in run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:179:in `call'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:179:in `run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_exec'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_eval_with_args'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:247:in `instance_eval_with_args'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:106:in `block (2 levels) in run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:108:in `call'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:108:in `run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:446:in `run_hook'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:340:in `run_around_each_hooks'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:256:in `with_around_each_hooks'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:111:in `run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:390:in `block in run_examples'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:386:in `map'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:386:in `run_examples'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:371:in `run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:28:in `map'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:28:in `block in run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/reporter.rb:58:in `report'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:25:in `run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/runner.rb:80:in `run'
     # /Users/stephenpuiszis/.rvm/rubies/ruby-2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.7/lib/rspec/core/runner.rb:17:in `block in autorun'

Finished in 0.23331 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/models/user_spec.rb:18 # User should require case sensitive unique value for uid

Randomized with seed 59157

@mcmire
Copy link
Collaborator

mcmire commented Oct 17, 2014

@stephen-puiszis Okay and only that test fails? No other test (well, at least validation test) fails?

@stephen-puiszis
Copy link
Author

Right, no other specs (in the entire app) are failing.

Failures:

  1) User should require case sensitive unique value for uid
     Failure/Error: it { should validate_uniqueness_of(:uid).allow_nil }
     ActiveRecord::StatementInvalid:
       PG::NotNullViolation: ERROR:  null value in column "first_name" violates not-null constraint
       DETAIL:  Failing row contains (1115, , , null, null, null, 0, null, null, null, null, 24608f9ae84eb83ee4315ebaa6147591ff4ff35537d8eb6b07cc71cdf9fbad22, null, 2014-10-17 18:44:54.367565, null, 2014-10-17 18:44:54.366393, 2014-10-17 18:44:54.366393, null, null, null, null, a).
       : INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "created_at", "uid", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
     # ./spec/models/user_spec.rb:18:in `block (2 levels) in <top (required)>'

Finished in 38.14 seconds
566 examples, 1 failure

Failed examples:

rspec ./spec/models/user_spec.rb:18 # User should require case sensitive unique value for uid

@mcmire
Copy link
Collaborator

mcmire commented Oct 21, 2014

@stephen-puiszis I'm stumped on this one too I'm afraid. Based on v2.7.0, I made a test similar to the following and it passed:

class User < ActiveRecord::Base
  validates :first_name, :last_name, presence: true
  validates :uid, uniqueness: true, allow_nil: true
end

describe User do
  subject do
    User.new(
      first_name: 'first name',
      last_name: 'last name'
    )
  end

  it { should validate_presence_of(:first_name) }
  it { should validate_presence_of(:last_name) }
  it { should validate_uniqueness_of(:uid).allow_nil }
end

Can you try commenting out some of the things from the model? Or even some tests? Or even some of the after :build's in the factories file?

@stephen-puiszis
Copy link
Author

@mcmire I'm still stumped and haven't been able to figure out why. However, one of the developers on our team developed this workaround:

 it { should allow_value(nil).for(:uid) }

  describe "unique uid" do
    before { user.update_attribute :uid, 12 }
    it { should validate_uniqueness_of(:uid) }
  end

@mcmire
Copy link
Collaborator

mcmire commented Feb 12, 2015

Since this seems to be an unexplainable edge case, and a workaround exists, I'm going to go ahead and close this issue. Feel free to comment if you find a solution, though.

@mcmire mcmire closed this as completed Feb 12, 2015
@rafaelgonzalez
Copy link

This happens to me as well when I have a non-null constraint on my model.

# db/migrate/create_channel_articles.rb

class CreateChannelArticles < ActiveRecord::Migration
  def change
    create_table :channel_articles do |t|
      t.integer :article_id, null: false, index: true
      t.integer :channel_id, null: false, index: true

      t.index [:article_id, :channel_id], unique: true

      t.timestamps null: false
    end
  end
end
# app/model/channel_article.rb

class ChannelArticle < ActiveRecord::Base
  belongs_to :article
  belongs_to :channel

  validates :article, :channel, presence: true
  validates :article_id, uniqueness: { scope: :channel_id }
end
# specs/models/channel_article_spec.rb

require 'rails_helper'

RSpec.describe ChannelArticle, type: :model do
  it { should belong_to(:article) }
  it { should belong_to(:channel) }

  it { should validate_presence_of(:article) }
  it { should validate_presence_of(:channel) }

  it { should validate_uniqueness_of(:article_id).scoped_to(:channel_id) }
end

I get the following:

 1) ChannelArticle should require case sensitive unique value for article_id scoped to channel_id
     Failure/Error: it { should validate_uniqueness_of(:article_id).scoped_to(:channel_id) }
     ActiveRecord::StatementInvalid:
       PG::NotNullViolation: ERROR:  null value in column "channel_id" violates not-null constraint
       DETAIL:  Failing row contains (2, 0, null, 2015-03-20 04:19:03.246573, 2015-03-20 04:19:03.246573).
       : INSERT INTO "channel_articles" ("article_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:602:in `exec_prepared'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:602:in `block in exec_cache'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract_adapter.rb:466:in `block in log'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract_adapter.rb:460:in `log'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:601:in `exec_cache'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:585:in `execute_and_clear'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:160:in `exec_query'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:192:in `exec_insert'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:108:in `insert'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `insert'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/relation.rb:64:in `insert'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/persistence.rb:521:in `_create_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/counter_cache.rb:139:in `_create_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:127:in `_create_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/callbacks.rb:306:in `block in _create_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:88:in `call'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:88:in `_run_callbacks'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:734:in `_run_create_callbacks'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/callbacks.rb:306:in `_create_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/timestamp.rb:57:in `_create_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/persistence.rb:501:in `create_or_update'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/callbacks.rb:302:in `block in create_or_update'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:117:in `call'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:117:in `call'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:169:in `block in halting'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:169:in `call'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:169:in `block in halting'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:92:in `call'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:92:in `_run_callbacks'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:734:in `_run_save_callbacks'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/callbacks.rb:302:in `create_or_update'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/persistence.rb:120:in `save'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/validations.rb:37:in `save'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:21:in `save'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:286:in `block (2 levels) in save'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:347:in `block in with_transaction_returning_status'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/transaction.rb:188:in `within_new_transaction'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:220:in `transaction'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:344:in `with_transaction_returning_status'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:286:in `block in save'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:301:in `rollback_active_record_state!'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.0/lib/active_record/transactions.rb:285:in `save'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:306:in `block in create_record_in_database'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:303:in `tap'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:303:in `create_record_in_database'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:279:in `first_instance'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:275:in `existing_record'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:335:in `block in set_scoped_attributes'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:332:in `each'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:332:in `all?'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:332:in `set_scoped_attributes'
     # /Users/rafaelgonzalez/.rvm/gems/ruby-2.2.1/gems/shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb:245:in `matches?'
     # ./spec/models/channel_article_spec.rb:11:in `block (2 levels) in <top (required)>'

It's like it is creating the model without setting the attributes that have null constraints on them. If I remove the non-null constraint from my migration and regenerate the DB, the tests pass.

EDIT: Updated with the proper error message.

@rafaelgonzalez
Copy link

Also note that doing this instead:

# app/model/channel_article.rb
validates :article, uniqueness: { scope: :channel }

# specs/models/channel_article_spec.rb
it { should validate_uniqueness_of(:article).scoped_to(:channel) }

Leads me to this other problem: #535

@rafaelgonzalez
Copy link

Most likely related to #194 as well.

@mcmire
Copy link
Collaborator

mcmire commented Mar 20, 2015

@rafaelgonzalez Yeah, your issue is related to #194. But this is different -- here, none of the columns in the uniqueness validation involve first_name, so there should be no reason that the null constraint should be getting violated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants