3

ここでは、私の質問の基礎をなす最小のテストケースです。 userが正しく保存されていても、属性user.idは更新されないのはなぜですか?データベース内のレコードを再検索しようとすると、問題なくフェッチされ、id属性が適切に設定されます。保存後に複合主キーが更新されない

AFAICT、これはsqliteの複合主キーを自動的にインクリメントしようとする試みではありません。同様の問題は、uuid/PostgreSQLの組み合わせでも発生します。スキーマの主キーはidで、[ :account_id, :id ]は別個の一意のインデックスです。

#!/usr/bin/env ruby 
gem "rails", "~> 5.0.2" 
gem "composite_primary_keys" 

require "active_record" 
require "composite_primary_keys" 

ActiveRecord::Base.establish_connection(
    adapter: "sqlite3", 
    database: ":memory:" 
) 

ActiveRecord::Schema.define do 
    create_table :accounts, force: true do |t| 
    end 

    create_table :users, force: true do |t| 
    t.references :account 
    t.index [ :account_id, :id ], unique: true 
    end 
end 

class User < ActiveRecord::Base 
    self.primary_keys = [ :account_id, :id ] 
    belongs_to :account, inverse_of: :users 
end 

class Account < ActiveRecord::Base 
    has_many :users, inverse_of: :account 
end 

account = Account.create! 
puts "created account: #{account.inspect}" 
user = account.users.build 
puts "before user.save: #{user.inspect}" 
user.save 
puts "after user.save: #{user.inspect}" 
puts "account.users.first: #{account.users.first.inspect}" 

そして、そのスクリプトを実行した結果は次のとおりです。

~/src 
[email protected](ttys005)[4146] % ./cpk-test.rb 
-- create_table(:accounts, {:force=>true}) 
    -> 0.0036s 
-- create_table(:users, {:force=>true}) 
    -> 0.0009s 
created account: #<Account id: 1> 
before user.save: #<User id: nil, account_id: 1> 
after user.save: #<User id: nil, account_id: 1> 
account.users.first: #<User id: 1, account_id: 1> 

は、最初は、保存した後[1,1]ことUSER.IDないでしょうか?これがバグであれば、誰に報告すればよいですか?

+1

私はちょうど実際には単一のファイルで作業例を与えるために親指を与えたいと思った、私はこれが焦点を当てていた多くの質問をしたいです。 – Iceman

+1

ありがとうございますが、この優れた記事を投稿してくれたJon Leightonに感謝しています。 http://www.jonathanleighton.com/articles/2011/awesome-active-record-bug-reports/ –

答えて

0

結局のところ、答えは単純なものでした。 Railsは通常、返された主キーをcreateから取得し、それを使ってモデルを更新します。コンポジットキーは独自にリロードされないので、私はそれを行う必要があります。作成されたレコードをフェッチしてそれに応じて属性を更新するには、基本的にafter_createフックでreloadのロジックを使用しました。

​​

そして今:

[email protected](ttys003)[4108] % ./cpk-test.rb 
-- create_table(:accounts, {:force=>true}) 
    -> 0.0045s 
-- create_table(:users, {:force=>true}) 
    -> 0.0009s 
before save user: #<User id: nil, account_id: 1, email: "[email protected]"> 
after save user: #<User id: 1, account_id: 1, email: "[email protected]"> 
0

SQLiteは複合主キーの自動インクリメントをサポートしていません。 SO:12に関連する質問があります。

ここで、第2のリンクから@SingleNegationElimination答え:sqliteので

唯一の整数 列が主キーであるとき、あなただけの自動インクリメント動作を得ます。複合キーにより、自動インクリメントが有効になるのを防ぐために、 が有効になります。

idを唯一の主キーとして定義すると、 が得られますが、id、col3に一意の制約が追加されます。

そして、composite_primary_keysは、そのロジックを保持します。ここ

もがそうするトリックが存在する:sqlite: multi-column primary key with an auto increment column

+0

問題を簡単に説明するためにsqliteを使用しています。 UUIDとPostgreSQLで同じ結果が得られます。レコードは正常に保存され、idは最終的には正しいですが、 'save'が呼び出されたインスタンスは、保存が完了した後に新しいIDを反映するように更新されません。 –

関連する問題