LoginSignup
6
7

More than 1 year has passed since last update.

foreigner の SQLite3 アダプタを書いた

Last updated at Posted at 2014-09-02

Rails 4.2 からの DB Migration は FK を標準でサポートする予定になっていますが、現時点では、多くの方が foreigner を使っている状況かと思います。

foreigner は SQLite3 の場合は処理をスキップするようになっています。

これは、まあ以下の issue でも回答されている通り、妥当なところではあって

SQLite3 はデフォルトでは off の pragma を有効にすれば FK を使うことも出来るのですが

SQLite3 は以下に明記されている通り

alter table の構文では、何と add column くらいしかまともにサポートしていないという状況で、他の RDBMS のように add constraint することができず、テーブルの再作成が必要になってしまいます。

実際、ActiveRecord の sqlite3_adapter に #remove_column が実装されていますが、こんな感じの力技です。

[1] pry(main)> ActiveRecord::Base.connection.remove_column("user", "company_id")
   (0.1ms)  begin transaction
   (1.1ms)  CREATE TEMPORARY TABLE "auser" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "company_id" integer NOT NULL, "created_at" datetime NOT NULL)
   (0.5ms)  SELECT * FROM "user"
   (1.1ms)  DROP TABLE "user"
   (0.2ms)  CREATE TABLE "user" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime NOT NULL)
   (0.1ms)  SELECT * FROM "auser"
   (0.3ms)  DROP TABLE "auser"
   (0.9ms)  commit transaction
=> []

そんな感じなので、ほとんどの方は MySQL なり PostgreSQL を development や test でも使えばいいじゃんというスタンスだと思うし、実際わざわざ違う RDBMS で動かす必要もないのですが、とはいえ、SQLite3 の手軽さは、デザイナーとの協業やら、普段触ってないプロジェクトをちょっと起動するときやら、CI の設定をするときやら、いろんなケースで嬉しいというのもまた事実です。

できれば FK を使った DB 設計のテストでも SQLite3 を使えないものか。ということで foreigner の SQLite3 で動作する adapter を実装してみました。

最初は ActiveRecord の remove_column とか使っていましたが、テーブル再作成するタイミングで元々ある FK の設定が失われてしまうため、sqlite_master テーブルから create table の DDL をとってきて置換するようにしました。

元々データがある時の扱いが結構厄介なのですが、とりあえずそういうケースでは標準出力に warning を出して foreigner と同様スキップしています。この辺は私は今すぐ必要とはしていないのですが、うまく実装できれば対応したいところです。

追記:2015/12

Rails 4.2 からは foreigner が存在すると正常に動作しなくなっています。
http://qiita.com/seratch@github/items/4cccda08f8ba96ac6173

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7