新手问题 [求解] 奇怪的异常: find_or_create_by!

dawei · 2019年10月10日 · 最后由 dawei 回复于 2019年10月11日 · 2198 次阅读
# email.rb
serialize :receive_permissions, Array
2.3.1 :042 > Email.find_or_create_by!(code: "TestEmail02", title: "TestEmail_02", receive_permissions: ["country", "high_end"])
  Email Load (0.4ms)  SELECT  "emails".* FROM "emails" WHERE "emails"."code" = $1 AND "emails"."title" = $2 AND "emails"."receive_permissions" IN ('country', 'high_end') LIMIT 1  [["code", "TestEmail02"], ["title", "TestEmail_02"]]
   (0.2ms)  BEGIN
  Email Exists (0.4ms)  SELECT  1 AS one FROM "emails" WHERE "emails"."code" = 'TestEmail02' LIMIT 1
  Email Exists (0.3ms)  SELECT  1 AS one FROM "emails" WHERE "emails"."title" = 'TestEmail_02' LIMIT 1
  SQL (0.3ms)  INSERT INTO "emails" ("code", "title", "receive_permissions", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5)
RETURNING "id"  [["code", "TestEmail02"], ["title", "TestEmail_02"], ["receive_permissions", "---\n- country\n- high_end\n"], ["created_at", "2019-10-10 17:59:54.716189"], ["updated_at", "2019-10-10 17:59:54.716189"]]
   (1.6ms)  COMMIT
 => #<Email id: 29, code: "TestEmail02", title: "TestEmail_02", description: nil, receive_permissions: ["country", "high_end"], created_at: "2019-10-10 09:59:54", updated_at: "2019-10-10 09:59:54">

2.3.1 :043 > Email.find_or_create_by!(code: "TestEmail02", title: "TestEmail_02", receive_permissions: ["country", "high_end"])
  Email Load (0.4ms)  SELECT  "emails".* FROM "emails" WHERE "emails"."code" = $1 AND "emails"."title" = $2 AND "emails"."receive_permissions" IN ('country', 'high_end') LIMIT 1  [["code", "TestEmail02"], ["title", "TestEmail_02"]]
   (0.2ms)  BEGIN
  Email Exists (0.3ms)  SELECT  1 AS one FROM "emails" WHERE "emails"."code" = 'TestEmail02' LIMIT 1
  Email Exists (0.4ms)  SELECT  1 AS one FROM "emails" WHERE "emails"."title" = 'TestEmail_02' LIMIT 1
   (0.2ms)  ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Code has already been taken, Title has already been taken
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/validations.rb:79:in `raise_record_invalid'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/validations.rb:43:in `save!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/transactions.rb:291:in `block in save!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/transactions.rb:220:in `transaction'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/transactions.rb:291:in `save!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/persistence.rb:51:in `create!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/relation.rb:151:in `block in create!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/relation.rb:302:in `scoping'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/relation.rb:151:in `create!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/relation.rb:219:in `find_or_create_by!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.3/lib/active_record/querying.rb:6:in `find_or_create_by!'
        from (irb):43
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/railties-4.2.3/lib/rails/commands/console.rb:110:in `start'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/railties-4.2.3/lib/rails/commands/console.rb:9:in `start'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:68:in `console'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
        from /Users/iewad/.rvm/gems/ruby-2.3.1/gems/railties-4.2.3/lib/rails/commands.rb:17:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'
2.3.1 :059 > Email.find_or_create_by!(code: "TestEmail07", title: "TestEmail_07") { |email| email.receive_permissions = ["country", "
area"] }
  Email Load (0.3ms)  SELECT  "emails".* FROM "emails" WHERE "emails"."code" = $1 AND "emails"."title" = $2 LIMIT 1  [["code", "TestEmail07"], ["title", "TestEmail_07"]]
   (0.3ms)  BEGIN
  Email Exists (0.7ms)  SELECT  1 AS one FROM "emails" WHERE "emails"."code" = 'TestEmail07' LIMIT 1
  Email Exists (0.4ms)  SELECT  1 AS one FROM "emails" WHERE "emails"."title" = 'TestEmail_07' LIMIT 1
  SQL (0.3ms)  INSERT INTO "emails" ("code", "title", "receive_permissions", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5)
RETURNING "id"  [["code", "TestEmail07"], ["title", "TestEmail_07"], ["receive_permissions", "---\n- country\n- area\n"], ["created_at", "2019-10-10 18:45:22.970299"], ["updated_at", "2019-10-10 18:45:22.970299"]]
   (1.8ms)  COMMIT
 => #<Email id: 34, code: "TestEmail07", title: "TestEmail_07", description: nil, receive_permissions: ["country", "area"], created_at: "2019-10-10 10:45:22", updated_at: "2019-10-10 10:45:22">
2.3.1 :060 > Email.find_or_create_by!(code: "TestEmail07", title: "TestEmail_07") { |email| email.receive_permissions = ["country", "area"] }
  Email Load (0.4ms)  SELECT  "emails".* FROM "emails" WHERE "emails"."code" = $1 AND "emails"."title" = $2 LIMIT 1  [["code", "TestEmail07"], ["title", "TestEmail_07"]]
 => #<Email id: 34, code: "TestEmail07", title: "TestEmail_07", description: nil, receive_permissions: ["country", "area"], created_at: "2019-10-10 10:45:22", updated_at: "2019-10-10 10:45:22">

没有什么奇怪的,仔细看 sql。

你第一次执行的时候,存入的 receive_permissions 是序列化的数组,而第二次查询时,receive_permissions: ["country", "high_end"],sql 实际是个 in 语句:"emails"."receive_permissions" IN ('country', 'high_end'),自然就找不到上一次存入的记录。接下来就会执行 create,然而 code 和 title 的 validation 没有通过,自然就报错了

dawei 关闭了讨论。 10月11日 09:52
需要 登录 后方可回复, 如果你还没有账号请 注册新账号