为什么设计注册#create,:trackable执行INSERT而不是UPDATE?

时间:2016-01-19 19:42:44

标签: postgresql ruby-on-rails-4 devise

嗨,我在运行MRI 2.2.3的Rails 4.2.4应用程序中使用Devise 3.5.3:

app/models/user.rb:
  devise :confirmable, :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable

以下是导致问题的流程:

  1. 使用单个属性提交新的注册表单:电子邮件
  2. 用户的before_validation回调成功添加了必需的属性:pid
  3. Devise Registraion控制器执行必要属性的INSERT(:email,:pid,:created_at,:confirmation_token等...)
  4. 设计:确认发送确认电子邮件
  5. 设计:可跟踪收集它为先前插入的用户记录跟踪的5个属性
  6. 然后,问题:

    1. 设计INSERT(而不是UPDATE)
    2. Postgres会在必需的列" pid"
    3. 上抛出NotNullViolation
    4. 之前插入了pid,因此UPDATE可以避免使用NotNullViolation
    5. Arrggh!
    6. 说明:

      1. 我使用email only sign up as described in Devise wiki,只接收邮件到POST注册#create。
      2. 我也使用guest user strategy as described in the Devise wiki,但在这种情况下无关紧要。
      3. 用户表具有设计所需的所有必填字段。
      4. 使用Devise观察其他rails项目,:确认和:trackable,Devise正确更新记录(上面的步骤#6)。
      5. 注册控制器,标准设备没有自定义。
      6. 问题:

        1. 为什么:可跟踪执行INSERT而不是UPDATE?
        2. 如何解决并修复这个悲伤的应用程序?
        3. 无奈:

          1. 当我第一次建造它时,我可以发誓这是有效的。 : - (
          2. 我的letter_opener-1.4.1 gem已经停止工作,原因不明。有关?
          3. 以下是相关的日志数据:

            Started POST "/users" for ::1 at 2016-01-19 08:42:12 -0800
            Processing by RegistrationsController#create as HTML
              Parameters: {"utf8"=>"✓", "authenticity_token"=>"VINuBSmtWh2j7oVY0JgGqHB/d7Ue6YZOdnEfGjGlwU7sY0GD0dvmQ0hSBxzGGQlM4i+h5sByMVanRWo2y0mqqA==", "user"=>{"email"=>"admin@test.com"}, "commit"=>"Join"}
               (0.1ms)  BEGIN
               (0.6ms)  SELECT "users"."pid" FROM "users"
              User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."confirmation_token" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["confirmation_token", "f8da655cda392edf619184fac68b3d03728c3a34abfc99e3026d1727a8d2964e"]]
              SQL (0.4ms)  INSERT INTO "users" ("email", "pid", "created_at", "updated_at", "confirmation_token", "confirmation_sent_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["email", "admin@test.com"], ["pid", "isgt"], ["created_at", "2016-01-19 16:42:12.148537"], ["updated_at", "2016-01-19 16:42:12.148537"], ["confirmation_token", "tsK97z8Ae2jNzKxUCPyj"], ["confirmation_sent_at", "2016-01-19 16:42:12.379778"]]
              Rendered devise/mailer/confirmation_instructions.html.slim (3.8ms)
            
            Devise::Mailer#confirmation_instructions: processed outbound mail in 222.8ms
            
            Sent mail to admin@test.com (368.0ms)
            Date: Tue, 19 Jan 2016 08:42:12 -0800
            From: team@example.com
            Reply-To: team@example.com
            To: admin@test.com
            Message-ID: <569e6764987cf_170e83ff5065e9ae4779a7@flat-top.local.mail>
            Subject: Confirmation instructions
            Mime-Version: 1.0
            Content-Type: text/html;
             charset=UTF-8
            Content-Transfer-Encoding: 7bit
            
            <p>
              Welcome admin@test.com!
            </p>
            <p>
              You can confirm your account email through the link below:
            </p>
            <p>
              <a href="http://localhost:3000/users/confirmation?confirmation_token=tsK97z8Ae2jNzKxUCPyj">Confirm my account</a>
            </p>
              User Exists (0.5ms)  SELECT  1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('admin@test.com') AND "users"."id" != 80) LIMIT 1
               (0.3ms)  ROLLBACK
               (0.1ms)  BEGIN
              SQL (8.9ms)  INSERT INTO "users" ("last_sign_in_at", "current_sign_in_at", "last_sign_in_ip", "current_sign_in_ip", "sign_in_count") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["last_sign_in_at", "2016-01-19 16:42:13.006971"], ["current_sign_in_at", "2016-01-19 16:42:13.006971"], ["last_sign_in_ip", "::1/128"], ["current_sign_in_ip", "::1/128"], ["sign_in_count", 1]]
            PG::NotNullViolation: ERROR:  null value in column "pid" violates not-null constraint
            DETAIL:  Failing row contains (81, null, null, null, null, user, , , null, null, null, 1, 2016-01-19 16:42:13.006971, 2016-01-19 16:42:13.006971, ::1, ::1, null, null, null, null, null, null, null, null, null, null, null, null).
            : INSERT INTO "users" ("last_sign_in_at", "current_sign_in_at", "last_sign_in_ip", "current_sign_in_ip", "sign_in_count") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
               (0.1ms)  ROLLBACK
            Completed 500 Internal Server Error in 876ms (ActiveRecord: 11.7ms)
            
            PG::NotNullViolation - ERROR:  null value in column "pid" violates not-null constraint
            DETAIL:  Failing row contains (81, null, null, null, null, user, , , null, null, null, 1, 2016-01-19 16:42:13.006971, 2016-01-19 16:42:13.006971, ::1, ::1, null, null, null, null, null, null, null, null, null, null, null, null).
            

1 个答案:

答案 0 :(得分:0)

我发现有一个验证错误导致第一个INSERT 无声地失败所以当:trackable出现时,记录不存在更新。如果我注意到没有返回COMMIT消息,我会更快地想出来。

如果它帮助了其他人,这是解决验证错误后的日志条目:

Started POST "/users" for ::1 at 2016-01-19 12:17:54 -0800
  ActiveRecord::SchemaMigration Load (0.4ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"s7xFg67CJ85OCnkZKROPkzNRBCWw3hhJQiUW0FeHLdjSBzPP8jMvIgaCVxJFPbA59UnBOZisA8h7lntvaqtJ4w==", "user"=>{"email"=>"admin@test.com"}, "commit"=>"Join"}
   (0.2ms)  BEGIN
   (0.6ms)  SELECT "users"."pid" FROM "users"
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."confirmation_token" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["confirmation_token", "ebb817b51ee9a457f75fe58d1fd29f19fb0c64cbd65122cdbe1935e8c56e48ab"]]
  SQL (0.4ms)  INSERT INTO "users" ("email", "pid", "created_at", "updated_at", "confirmation_token", "confirmation_sent_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["email", "admin@test.com"], ["pid", "93412"], ["created_at", "2016-01-19 20:17:54.650641"], ["updated_at", "2016-01-19 20:17:54.650641"], ["confirmation_token", "vEPtNFijrDhw5TjFh1Qy"], ["confirmation_sent_at", "2016-01-19 20:17:54.861593"]]
  Rendered devise/mailer/confirmation_instructions.html.slim (14.5ms)

Devise::Mailer#confirmation_instructions: processed outbound mail in 301.6ms

Sent mail to admin@test.com (334.7ms)
Date: Tue, 19 Jan 2016 12:17:55 -0800
From: team@example.com
Reply-To: team@example.com
To: admin@test.com
Message-ID: <569e99f32d4b0_dcb3ff7a2548e707039@flat-top.local.mail>
Subject: Confirmation instructions
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

<p>
  Welcome admin@test.com!
</p>
<p>
  You can confirm your account email through the link below:
</p>
<p>
  <a href="http://localhost:3000/users/confirmation?confirmation_token=vEPtNFijrDhw5TjFh1Qy">Confirm my account</a>
</p>
  User Exists (0.5ms)  SELECT  1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('admin@test.com') AND "users"."id" != 10) LIMIT 1
   (6.4ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.3ms)  UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "last_sign_in_ip" = $3, "current_sign_in_ip" = $4, "sign_in_count" = $5, "updated_at" = $6 WHERE "users"."id" = $7  [["last_sign_in_at", "2016-01-19 20:17:55.540280"], ["current_sign_in_at", "2016-01-19 20:17:55.540280"], ["last_sign_in_ip", "::1/128"], ["current_sign_in_ip", "::1/128"], ["sign_in_count", 1], ["updated_at", "2016-01-19 20:17:55.541519"], ["id", 10]]
   (6.0ms)  COMMIT