QA@IT

Rails4での外部結合を使っている場合のDatabaseRewinder

5283 PV
  • Rails4.1.4
  • Rspec 3.0.0

の環境で、Postgresql(brewでv 9.3.5)を使用しています。

  • gem foreigner を用いて外部結合を使った設計をしていた
  • rspec でDatabaseRewinder.clean_allしている
  • モデル、コントローラのテストを順調に作っていた

  • MacOSを再インストールして環境を作りなおした

その後。環境再構築後から、

PG::ForeignKeyViolation: ERROR:  update or delete on table "courses" violates foreign key constraint "services_course_id_fk" on table "services" (ActiveRecord::InvalidForeignKey)
DETAIL:  Key (id)=(0) is still referenced from table "services".

と、エラーが出るようになりました。
外部結合の制約をつけているので、当然のエラーだと思いますが、

  • なぜ、環境再構築前はDatabaseRewinder.clean_allできてたのか。(外部制約が設定されていたのは確認してます)
  • foreignerを用いた場合、DatabaseRewinder.clean_allでこのエラーが出てしまうの回避できるのか?

というのが質問です。

念のため、rails_helper.rbの内容です。

ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/rails' #require 'rspec/autorun'
require 'email_spec'
require 'shoulda-matchers'
require 'capybara/rails'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
require 'capybara/poltergeist' #require 'capybara/webkit'
require 'devise'
Capybara.javascript_driver = :poltergeist_debug
Capybara.register_driver :poltergeist_debug do |app|
  Capybara::Poltergeist::Driver.new(
    app, inspector: true, js_errors: false, timeout: 120
  )
end
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
  config.before :suite do
    OmniAuth.config.test_mode = true
    FactoryGirl.reload
    DatabaseRewinder.clean_all
    require Rails.root.join('db', 'seeds.rb')
  end

  config.after :each do
    DatabaseRewinder.clean
  end
  config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!

  ## Capybara
  config.include Capybara::DSL # capybara configration

  # FactoryGirl
  config.include FactoryGirl::Syntax::Methods # factorygirl FactoryGirlを省略

  # EmailSpec
  config.include(EmailSpec::Helpers)
  config.include(EmailSpec::Matchers)

  # Devise etc..
  config.include Devise::TestHelpers, type: :controller
  config.include OmniauthMacros
  config.extend ControllerMacros
end

よろしくお願いいたします。

回答

Rails 4.2.1 と database_rewinder 0.5.2 で同じ問題にはまったので調べてみたところ、 http://tech.aquarite.info/blog/2015/03/12/database-rewinder-with-rails-4-2/ に書いてあるようにテストデータベースにアクセスしているロールにスーパーユーザー権限がないとエラーになるようです。

環境を作りなおす前はスーパーユーザー権限が付いていたのに、環境を作りなおした後はスーパーユーザー権限をつけなかったのではないでしょうか。

手元で問題が起きていた環境では、参考にしたブログに書いてあったように

ALTER ROLE username WITH SUPERUSER;

でスーパーユーザー権限をつけると解決しました。(権限の確認は \du でできます)

編集 履歴 (0)
  • ありがとうございます。DB絡みの場合、DB側の設定もキにしておかないといけないんですね。外部結合は使わないようにしてましたがこれで今後は使ってみようと思います。ありがとうございました。 -

補足です(コメントだと見難いので

DatabaseCleanerに変更すると、テストが通るようになりました(外部結合エラーが出なくなりました)

  • database_cleaner-1.3.0
  • database_rewinder-0.2.0
RSpec.configure do |config|
  config.before :suite do
    OmniAuth.config.test_mode = true
    FactoryGirl.reload
    #DatabaseRewinder.clean_all
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
    require Rails.root.join('db', 'seeds.rb')
  end

  config.before :each do
    DatabaseCleaner.start
    #I18n.locale = :ja
  end

  config.after :each do
    #DatabaseRewinder.clean
    DatabaseCleaner.clean
  end

  ・・省略

違いはなんなのでしょう。

編集 履歴 (0)
  • 上記のままでもREADMEにあるよに、DatabaseCleaner = DatabaseRewinderとしてみたらエラーになります。Cleanerはtruncate(cascade)でrewinderはdeleteだからでしょうか?

    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。