すでに存在するRailsの自動割り当てID


92

次のように新しいレコードを作成します。

truck = Truck.create(:name=>name, :user_id=>2)

私のデータベースには現在トラック用に数千のエンティティがありますが、いくつかのIDを利用できるように、それらのいくつかにIDを割り当てました。つまり、railsはid = 150のアイテムを作成し、正常に機能しています。しかし、それからアイテムを作成してid = 151を割り当てようとしますが、そのidはすでに存在している可能性があるため、次のエラーが表示されます。

ActiveRecord::RecordNotUnique (PG::Error: ERROR: duplicate key value violates unique constraint "companies_pkey" DETAIL: Key (id)=(151) already exists.

そして、次にアクションを実行するとき、ID 152が割り当てられます。これは、その値がまだ取得されていない場合に正常に機能します。IDを割り当てる前に、IDがすでに存在するかどうかをレールで確認するにはどうすればよいですか?

ありがとう!

編集する

トラックIDは複製されるものです。ユーザーは既に存在し、この場合は定数です。これは、私が対処しなければならないレガシー問題です。1つのオプションとして、今回はすべてのIDをレールが自動割り当てできるようにテーブルを再作成します。他にもいくつか問題があるため、これが最良の選択であると考え始めていますが、トラックは他の多くのテーブルの外部キーであるため、これを行うための移行は非常に複雑になります。自動割り当てされたIDを使用して既存のすべての関係を維持しながら、Trailにすでに保存されている同じデータを使用してRailsが新しいテーブルを作成する簡単な方法はありますか?


なぜレールに自動的にIDを割り当てさせないのですか?これは重複の危険性を排除しますか、それとも古いIDを保持する必要があるレガシーデータの問題ですか?新しいオブジェクトを作成するとき、これは通常のビジネスではないので、ビジネスケースを少し理解したいだけです。
MBHNYC、2012年

@MBHNYC D-Niceは会社の作成中にuser_idを割り当てていると思います。あなたが考えているように、idではありません(私も少しの間)。
Anil

うーん良いキャッチアニル-あなたは完全に正しいです。@ D-Nice、何か変なことがあった場合に備えて、このテーブルの移行を投稿に追加してください。混乱を避けるためにそのuser_idを編集し
たくなる

いいえ、わかりませんでした。会社IDが重複しています。ユーザーはすでに存在しており、この場合は定数です。それは実際に私が対処しなければならないレガシー問題です。詳細情報を含む投稿を編集します
D-Nice

テーブルを再作成する必要はありません。シーケンスをリセットするには、私の回答をご覧ください。
Dondi Michael Stroma

回答:


87

Railsはおそらく組み込みのPostgreSQLシーケンスを使用しています。シーケンスの概念は、それが1回だけ使用されるということです。

最も簡単な解決策は、次のようなクエリを使用して、company.id列のシーケンスをテーブルの最大値に設定することです。

SELECT setval('company_id_seq', (SELECT max(id) FROM company));

シーケンス名「company_id_seq」、テーブル名「company」、および列名「id」であると思います...正しいものに置き換えてください。でシーケンス名を取得するSELECT pg_get_serial_sequence('tablename', 'columname');か、でテーブル定義を確認でき\d tablenameます。

別の解決策は、会社のクラスのsave()メソッドをオーバーライドして、保存する前に新しい行の会社IDを手動で設定することです。


私はそれが何をするのでしょうか?自動割り当てが現在最も高い値+1で始まるものから始まると思いますか?
D-Nice

これが私の質問に対する最良の答えだと思いますが、無関係な理由により、私はOP編集で説明した戦略を使用する方法を見つける必要があります
D-Nice

なぜこれが偶然始まったのか理解できませんか?これは私にも起こりました。これがどのようにして可能かを理解したいと思います。
バーディックハント14

2
@ Websitescenes、PostgreSQLにSERIAL列がある場合(シリアル列は、デフォルト値がシーケンスの次の値である列)、テーブルにその列のハード値を入力すると、シーケンスは自動的に更新されません。例: create table t (id serial not null primary key); insert into t values (1); insert into t values (default); ERROR: duplicate key value violates unique constraint "t_pkey" DETAIL: Key (id)=(1) already exists.
Dondi Michael Stroma 2014年

204

私はこれをやって、私のために問題を解決しました。

ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end

reset_pk_sequenceが見つかりました!このスレッドから。http://www.ruby-forum.com/topic/64428


4
ありがとう、最善の解決策。データベース転送後、同じ問題が発生しました。
Oleg Pasko 2013

61
または、ワンライナーの同等物(Railsコンソールのコピー/貼り付け目的):ActiveRecord::Base.connection.tables.each { |t| ActiveRecord::Base.connection.reset_pk_sequence!(t) }
Raf

これが同期しなくなる方法はありますか?
トールポール

25

@Apieの回答に基づいています

タスクを作成して、必要なときに実行できます。

rake database:correction_seq_id

次のようなタスクを作成します。

rails g task database correction_seq_id

そして、生成されたファイルに(lib/tasks/database.rake)を入れます:

namespace :database do
    desc "Correction of sequences id"
    task correction_seq_id: :environment do
        ActiveRecord::Base.connection.tables.each do |t|
            ActiveRecord::Base.connection.reset_pk_sequence!(t)
        end
    end
end

4

Railsの問題ではなく、データベースの問題のように思えます。データベースのid列に不適切なIDシードがある可能性はありますか?テストするには、データベースに直接いくつかの挿入を行い、同じ動作が存在するかどうかを確認してください。


3
なぜ反対票か。これは、インクリメントシーケンスを他の既存の値よりも低い値に設定した場合に発生する正確な動作であり、データを挿入するときに衝突が発生する場合があります。ポスターはすでに、このケースに該当する既存のデータがあると述べました。
mynameiscoffey 2012年

うまく挿入できます。このエラーが発生した後、シーケンスの次のIDがまだ取得されていない場合は、実際に同じアクションを再度実行して機能させることができます。
D-Nice

これは私の状況のようです-私は問題に遭遇しましたが、挿入した次のレコードはうまくいきました、それでそれは正しい場所に種を得たに違いありません。
ベンウィーラー

3

次のコマンドでこの問題を解決しました。

これをRailsコンソールで実行します

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.