rails 主键非 id 查询的奇怪 ORM 行为

Odd ORM behavior for rails query with non id for primary key

给定一个由遗留 table 支持的模型,其中主键是 unique_id 而不是 id 当我使用 id 查询模型时(例如 CustomerLocations.where(id: 123)) 查询找到了正确的记录,但显示 id 列的错误值。此外,如果我引用该记录的 id,我将获得主键(即 unique_id)而不是 id.

请注意,id 列是 4457777,PK 是 53710
irb(main):001:0> customer = CustomerLocations.where(id: 445777).first
  CustomerLocations Load (0.3ms)  SELECT `customer_locations`.* FROM `customer_locations` WHERE `customer_locations`.`id` = 445777
=> #<CustomerLocations id: 53710, unique_id: 53710, name: "Joe Smith", ... >

irb(main):002:0> customer.first.id
=> 53710 # this is the unique id, should have returned 445777

如果我运行同样SQL查询,返回的id值是正确的445777,非pk。

mysql> SELECT id, unique_id FROM customer_locations WHERE id = 445777;
+--------+-----------+
| id     | unique_id |
+--------+-----------+
| 445777 |     53710 |
+--------+-----------+
1 row in set (0.00 sec)
这是模型:
class LegacyBase < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "ourlegacyprefix_#{Rails.env}".to_sym
  #...
end

class CustomerLocations < LegacyBase
  self.primary_key = :unique_id
  self.table_name = "customer_locations"

  belongs_to :customer, foreign_key: 'id'
  #...
end

class LegacyCustomer < GnpcbBase
  self.table_name = "legacy_customers"
  has_many  :customer_locations,
    foreign_key: 'id',
    dependent: :destroy

  belongs_to :customer_location
  #...
end

class Customer < ActiveRecord::Base
  belongs_to :legacy_customer
  #...
end

这是我的一些 gemspec

ruby '2.3.1'

gem 'rails', '5.0.0'
gem 'mysql2', '0.4.4'

这是客户的架构,customer_locations

  create_table "customer_locations", primary_key: "unique_id", force: :cascade do |t|
    t.integer "id",            limit: 4,     default: 0,    null: false
    t.string  "location_id",   limit: 10,    default: "",   null: false
    t.string  "name",          limit: 60
    t.text    "address",       limit: 65535
    t.string  "city",          limit: 50
    t.string  "state",         limit: 50
    t.string  "zip",           limit: 20
    t.string  "country",       limit: 2,     default: "US", null: false
    t.string  "phone",         limit: 50
    t.string  "email",         limit: 100
    t.string  "location_type", limit: 20
    t.date    "last_modified"
    t.string  "checksum",      limit: 8
  end

  add_index "customer_locations", ["id"], name: "id", using: :btree
  add_index "customer_locations", ["location_id"], name: "location_id_unique", unique: true, using: :btree

  create_table "customers", force: :cascade do |t|
    t.string "name",              limit: 255, default: "", null: false
    t.string "last_name",         limit: 50,  default: "", null: false
    t.string "first_name",        limit: 30,  default: "", null: false
    t.string "customer_category", limit: 20,  default: "", null: false
    t.string "customer_type",     limit: 20,  default: "", null: false
    t.string "customer_class",    limit: 20,  default: "", null: false
    t.date   "last_modified"
  end

这是我的模型配置错误还是 Rails 错误?

编辑 注意:如果我在 customer_locations 上将主键设置为 :id 那么它可以工作,但这当然与 table 结构的 pk 冲突。

情况相当混乱... 我会尝试重新映射 id 列:

class CustomerLocations < LegacyBase
  ...
  alias_attribute :secondary_id, :id
end

因此您可以通过 secondary_id

访问它

因为记住 id 是一种方法,而不是实际的列。如果您调用方法 id,它将 return primary key 值。如果可能的话,我认为你需要先修复你的设置。或者,现在您可以重写模型内部的 id 方法,例如:

def id
  _read_attribute(:id)
end