1

大規模な移行のスクリプトを作成していて、大きな問題に遭遇しました。

# Import users
user_data.each do |data|
  u = User.new
  u.id = data.id
  u.email = data.email
  # more user attributes set...
  u.save!
end

# required to prevent Postgres from trying to use now taken user ids
ActiveRecord::Base.connection.execute "ALTER SEQUENCE users_id_seq RESTART WITH #{User.last.id+1};"

そのため、最初にデータ ソースからユーザー データを読み取り、その ID を手動で設定します。関連データも移行するため、ID を保持する必要があります。

その後、関連付けられたオブジェクトのデータから条件付きでさらにユーザーを作成する必要があります。

# Create a user for this email if no user with this email exists.
if data.email
  user = User.find_by_email(data.email)
  if user
    o.user = user
  else
    o.user = User.create!(
      first_name: 'Unknown',
      last_name:  'Unknown',
      email:      data.email,
      password:   generate_temp_password
    )
  end
end

これは次の場合に失敗しますUser.create!:

Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)

これを少しデバッグしたところ、このエラーがスローされる直前であることUser.where(email: data.email).firstがわかりました。nilこれは、現在の自動インクリメント値を超えて id を設定することに何か関係があると思われます。何らかの理由で新しいレコードがクエリで見えなくなりますが、Postgres 自身の検証では見えるようになります。

では、特定の電子メールを持つユーザーが存在しないのに、DB 検証エラーをトリガーするにはどうすればよいでしょうか?

4

1 に答える 1

1

どうやら、Devise はメールアドレスを小文字にします。そして、問題のあるメールにはいくつかの大文字が含まれていました。そのため、大文字と小文字を区別するチェックを逃し、大文字と小文字を区別しないと、だまされて失敗しました。

工夫は私を裏切ったようです。

于 2013-09-12T18:33:02.080 に答える