在 rails 模型函数中查询另一个模型

querying another model in a rails model function

基本上,我想做的是加入文本字段而不是像

这样的 ID
SELECT country.delivery_time 
FROM order, country
WHERE order.country = country.name

到目前为止我的 Rails 模型是

class Country < ApplicationRecord
  validates :name, presence: true
  validates :delivery_time, presence: true
end

class Order < ApplicationRecord
  validates :country, presence: true

  def shipping_time
    # want to get the correct country from the DB
    if self.country == country.name
      country.delivery_time
    else
      "unavailable"
    end
  end
end

其中 shipping_time 是应该 return 连接结果的函数。我得到的错误是

undefined method `country'

我正在使用 Ruby 3.0.3 和 Rails 7.0.0。

所以我最终使用 joins 函数来获得我想要的东西,

Order.joins("INNER JOIN countries ON orders.country = countries.name")

完整功能在哪里

def shipping_time
  relation = Order.joins("INNER JOIN countries ON orders.country = countries.name")
  if 1 == relation.count()
    relation[0].delivery_time
  else
    "unavailable"
  end
end

打破常规并使用任何类型的外键列实际上非常简单:

class AddCountryNameToOrders < ActiveRecord::Migration[7.0]
  def change
    add_column :orders, :country_name, :string
    # Some DB's may not allow foreign key constraints 
    # on non PK columns
    add_foreign_key :orders, :countries,
      column: :country_name,
      primary_key: :name
  end
end

class Order < ApplicationRecord
  validates :country, presence: true
  belongs_to :country, 
    foreign_key: :country_name,
    primary_key: :name
end

class Country < ApplicationRecord
  has_many :orders,
    foreign_key: :country_name,
    primary_key: :name
end

用作primary_key选项的列实际上不必是目标table的PK。简单地命名列 country 会导致名称冲突,除非您为关联选择不同的名称(并使它变得更加混乱)。

但是考虑到域,这是一个非常糟糕的主意。

国家确实会更改名称 - 最近的例子是北马其顿和埃斯瓦蒂尼。

而是使用普通的 integer/uuid 外键列并使用委托从国家/地区获取名称。

class Order < ApplicationRecord
  belongs_to :country
  delegate :name, to: :country,
                  prefix: true
end 

如果您想为 table 使用“自然”主键而不是代理键(例如自动生成的 ID),那么 ISO 3166 国家/地区代码是更好的选择。