web-dev-qa-db-ja.com

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

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

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

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

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

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

ありがとう!

編集

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

89
D-Nice

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

最も簡単な解決策は、次のようなクエリを使用して、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を手動で設定することです。

86

私はこれを行い、問題を解決しました。

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

199
Apie

@Apie answer に基づきます。

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

rake database:correction_seq_id

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

Rails g task database correction_seq_id

生成されたファイル(lib/tasks/database.rake)put:

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
25
inye

Railsの問題ではなく、データベースの問題のように思えます。データベースのid列に不適切なIDシードがある可能性はありますか?データベースに追加し、同じ動作が存在するかどうかを確認します。

4
mynameiscoffey

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

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

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
0
Jigar Bhatt