Rails 与导致 AssociationTypeMismatch 错误的字符串的关联

Rails associations with string causing AssociationTypeMismatch error

我的 DevicePurchase 模型中有以下内容 -

has_one :coupon_code, primary_key: 'coupon_code', foreign_key: 'name'

我正在开发的应用程序通过优惠券的名称(字符串,即 "SummerPromo123")将 DevicePurchase 与 CouponCode 相关联,而不是想法。我在上面添加的关联看起来有效,但是当我尝试 DevicePurchase.last.update(...) 时,我收到了这个 -

DevicePurchase.last.update(coupon_code: 'yLVDnw')
  DevicePurchase Load (2.4ms)  SELECT "device_purchases".* FROM "device_purchases" ORDER BY "device_purchases"."id" DESC LIMIT 1
  (0.2ms)  BEGIN
  (0.3ms)  ROLLBACK
ActiveRecord::AssociationTypeMismatch: CouponCode(#70224191762780) expected, got String(#70224129222500)
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/associations/association.rb:224:in `raise_on_type_mismatch!'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/associations/has_one_association.rb:25:in `replace'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/associations/singular_association.rb:17:in `writer'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/associations/builder/association.rb:78:in `coupon_code='
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/attribute_assignment.rb:42:in `public_send'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/attribute_assignment.rb:42:in `_assign_attribute'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/attribute_assignment.rb:29:in `block in assign_attributes'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/attribute_assignment.rb:23:in `each'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/attribute_assignment.rb:23:in `assign_attributes'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/persistence.rb:230:in `block in update'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/transactions.rb:330:in `block in with_transaction_returning_status'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/connection_adapters/abstract/database_statements.rb:203:in `block in transaction'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `within_new_transaction'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/connection_adapters/abstract/database_statements.rb:203:in `transaction'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/transactions.rb:209:in `transaction'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/transactions.rb:327:in `with_transaction_returning_status'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/activerecord-4.0.12/lib/active_record/persistence.rb:229:in `update'
  from (irb):55
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/railties-4.0.12/lib/rails/commands/console.rb:90:in `start'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/railties-4.0.12/lib/rails/commands/console.rb:9:in `start'
  from /Users/ryangrush/.rvm/gems/ruby-2.2.4@myautobrain/gems/railties-4.0.12/lib/rails/commands.rb:62:in `<top (required)>'
  from bin/rails:4:in `require'
  from bin/rails:4:in `<main>'2.2.4 :056 >

我在 Whosebug 找到了一些针对该错误的答案,但我认为问题出在我的关联上。

** 更新 **

如果我 运行 DevicePurchase.last.update(coupon_code: CouponCode.last) 我得到以下错误 -

SELECT 1 AS one FROM "coupon_codes" WHERE ("coupon_codes"."name" = 1188 AND "coupon_codes"."id" != 1188) LIMIT 1
PG::UndefinedFunction: ERROR:  operator does not exist: text = integer
LINE 1: ...FROM "coupon_codes"  WHERE ("coupon_codes"."name" = 1188 AND...
                                                             ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
: SELECT  1 AS one FROM "coupon_codes"  WHERE ("coupon_codes"."name" = 1188 AND "coupon_codes"."id" != 1188) LIMIT 1
   (0.2ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR:  operator does not exist: text = integer
LINE 1: ...FROM "coupon_codes"  WHERE ("coupon_codes"."name" = 1188 AND...
                                                             ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.

好的,问题是,您得到的关联名称和列名称相同。因此,当您尝试 DevicePurchase.last.update(coupon_code: 'yLVDnw') 时,Rails 认为您将传递给它一个 CouponCode 对象,而不是您现在拥有的 "string" 值。这就是你得到错误的原因。但是如果你像下面这样重命名关联,你应该没问题:

has_one :coupon,
  primary_key: 'coupon_code',
  foreign_key: 'name',
  class_name: 'CouponCode'