下記のモデルと対応するテーブル、3つずつ作成して実験しました。括弧内はカラムを表しています。
- Post(title)
- Tag(name)
- PostTag(post_id, tag_id)
db/shema.rbにadd_index :tags, :name, unique: true
を追加して、モデルにバリデーションを追加すると、エラーのスタックトレースが表示されます。
Loading development environment (Rails 4.2.3)
irb(main):001:0> Tag.create(name: "tag1")
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "tag1"], ["created_at", "2015-10-05 04:56:25.110261"], ["updated_at", "2015-10-05 04:56:25.110261"]]
SQLite3::ConstraintException: UNIQUE constraint failed: tags.name: INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES (?, ?, ?)
(0.1ms) rollback transaction
ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: tags.name: INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES (?, ?, ?)
from /Users/mitsuru/.rbenv/versions/2.2.2/gemsets/vainglory/gems/sqlite3-1.3.10/lib/sqlite3/statement.rb:108:in `step'
\# ...省略
commands_tasks.rb:39:in `run_command!'
from /Users/mitsuru/.rbenv/versions/2.2.2/gemsets/vainglory/gems/railties-4.2.3/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
次はsema.rbだけではなく、モデルにvalidates :name, uniqueness: true
を加えて試してみます。
irb(main):001:0> Tag.create(name: "tag1")
(0.1ms) begin transaction
Tag Exists (0.2ms) SELECT 1 AS one FROM "tags" WHERE "tags"."name" = 'tag1' LIMIT 1
(0.1ms) rollback transaction
=> #<Tag id: nil, name: "tag1", created_at: nil, updated_at: nil>
返り値がちゃんとありますね。これでRuby側のプログラムが止まらずに対処できるようになります。