Help us understand the problem. What is going on with this article?

RailsのseedでIDを直接指定する場合

More than 3 years have passed since last update.

Railsで初期データ投入をする際は、整合性の問題からIDは直接指定したい。
しかし、seedでIDを指定してしまうと、seedが終わって、いざデータを作成という段階で怒られてしまう。

irb
irb(main):023:0> boat = IrishCoffee::Boat.new(name: "Tester2")
.
.
irb(main):024:0> boat.save
.
.
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "ic_boats_pkey"
DETAIL:  Key (id)=(2) already exists.
: INSERT INTO "ic_boats" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"
    from /usr/local/lib/ruby/gems/2.3.0/gems/activerecord-5.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'

明らかに重複したIDを割り振ろうとしていることが解る。
では、IDはどうやって管理されているのかが気になるが、SQLのスキーマを見れば一目瞭然。

kinkai_develop=# \d
                  List of relations
 Schema |         Name         |   Type   |  Owner
--------+----------------------+----------+----------
 public | ar_internal_metadata | table    | kinkaicc
 public | ic_boats             | table    | kinkaicc
 public | ic_boats_id_seq      | sequence | kinkaicc
 public | ic_clubs             | table    | kinkaicc
 public | ic_clubs_id_seq      | sequence | kinkaicc
 public | ic_races             | table    | kinkaicc
 public | ic_races_id_seq      | sequence | kinkaicc
 .
 .

 kinkai_develop=# select * from ic_boats_id_seq;
  sequence_name  | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called
-----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 ic_boats_id_seq |          2 |           1 |            1 | 9223372036854775807 |         1 |           1 |      31 | f         | t
(1 row)

このtablename_id_seqのlast_value又はmax_valueがIDを管理しているのだろことは簡単に想像が付く。
しかし、このシーケンスをどうやって変更すれば良いかが思いつかなかったが、
http://edywrite.blogspot.jp/2012/07/ruby-on-rails3_31.html
にそのままが書かれていたので、ありがたく拝借することにする。

SQLでシーケンスを設定すればいいらしい。

 def reset_id(tablename)
  connection = ActiveRecord::Base.connection()
  connection.execute("select setval('#{tablename}_id_seq',(select max(id) from #{tablename}))")
end

上記をseedsに書いておいて、データの投入後に呼び出してやればIDはテーブルの最大値を設定してくれる。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした