rails: 一对多关联(belongs_to/has_one)

例如,如果应用程序中的每个供应商只有一个帐户,则可以像这样声明供应商模型:

01 创建 Supplier 和 Account 模型

你需要给 Account 模型添加 supplier_id 外键,以建立一对一的关联。

运行以下命令来生成 SupplierAccount 模型:

rails g model Supplier name:string
rails g model Account supplier:references

02 模型关联

接下来,在模型中定义一对一的关联。

  • Supplier 拥有一个 Account,因此使用 has_one
  • Account 属于一个 Supplier,因此使用 belongs_to

app/models/supplier.rb

class Supplier < ApplicationRecord
  has_one :account, dependent: :destroy
end
  • has_one :account 表示 Supplier 拥有一个 Account
  • dependent: :destroy 表示如果删除 Supplier,关联的 Account 也会被删除。

app/models/account.rb

class Account < ApplicationRecord
  belongs_to :supplier
end

belongs_to :supplier 表示 Account 属于一个 Supplier

03 示例使用

现在你可以通过以下方式创建 Supplier 和关联的 Account

# 创建一个供应商
supplier = Supplier.create(name: "Supplier A")

# 为供应商创建一个账户
account = supplier.create_account(account_number: "123456")

# 或者使用 build_account 来初始化账户,而不保存到数据库
account = supplier.build_account(account_number: "123456")
account.save

# 查找某个供应商的账户
supplier.account

# 查找某个账户的供应商
account.supplier

这种设置方式确保每个供应商只能有一个账户,并且它们之间是一对一的关联。

04 典型场景 User-Profile

典型场景举例

在实际项目中,一对一(`has_one` 和 `belongs_to`)关系用于表示两个实体之间的唯一对应关系。这种设计用于确保其中一个对象只能与另一个对象关联。以下是几个典型的应用场景:

### 1. **用户和个人资料(User 和 Profile)**
   - **场景**:用户注册后,通常会有一个与其关联的个人资料(如头像、地址、生日等),而这些信息可能与用户表分离。
   - **模型关系**:
     - `User` 拥有一个 `Profile`。
     - `Profile` 属于一个 `User`。
   - **示例**:
     ```ruby
     class User < ApplicationRecord
       has_one :profile, dependent: :destroy
     end

     class Profile < ApplicationRecord
       belongs_to :user
     end
     ```

### 2. **供应商和账户(Supplier 和 Account)**
   - **场景**:每个供应商有一个唯一的财务账户,用于处理支付和交易。
   - **模型关系**:
     - `Supplier` 拥有一个 `Account`。
     - `Account` 属于一个 `Supplier`。
   - **示例**:
     ```ruby
     class Supplier < ApplicationRecord
       has_one :account, dependent: :destroy
     end

     class Account < ApplicationRecord
       belongs_to :supplier
     end
     ```

### 3. **公司和地址(Company 和 Address)**
   - **场景**:一个公司可能有一个唯一的注册地址,这个地址与公司有着一对一的关系。
   - **模型关系**:
     - `Company` 拥有一个 `Address`。
     - `Address` 属于一个 `Company`。
   - **示例**:
     ```ruby
     class Company < ApplicationRecord
       has_one :address, dependent: :destroy
     end

     class Address < ApplicationRecord
       belongs_to :company
     end
     ```

### 4. **订单和发票(Order 和 Invoice)**
   - **场景**:每个订单都有唯一的发票,发票记录与订单的支付信息和细节。
   - **模型关系**:
     - `Order` 拥有一个 `Invoice`。
     - `Invoice` 属于一个 `Order`。
   - **示例**:
     ```ruby
     class Order < ApplicationRecord
       has_one :invoice, dependent: :destroy
     end

     class Invoice < ApplicationRecord
       belongs_to :order
     end
     ```

### 5. **车辆和车主信息(Vehicle 和 OwnerInfo)**
   - **场景**:每辆车都只有一个车主信息(如身份证号、驾驶证号等),这是车辆的唯一属性。
   - **模型关系**:
     - `Vehicle` 拥有一个 `OwnerInfo`。
     - `OwnerInfo` 属于一个 `Vehicle`。
   - **示例**:
     ```ruby
     class Vehicle < ApplicationRecord
       has_one :owner_info, dependent: :destroy
     end

     class OwnerInfo < ApplicationRecord
       belongs_to :vehicle
     end
     ```

### 6. **员工和工资单(Employee 和 Payslip)**
   - **场景**:每位员工每个月生成一份工资单,这是与员工的唯一对应记录。
   - **模型关系**:
     - `Employee` 拥有一个 `Payslip`。
     - `Payslip` 属于一个 `Employee`。
   - **示例**:
     ```ruby
     class Employee < ApplicationRecord
       has_one :payslip, dependent: :destroy
     end

     class Payslip < ApplicationRecord
       belongs_to :employee
     end
     ```

### 7. **商品和库存信息(Product 和 Stock)**
   - **场景**:每个商品只有一个库存信息,用于记录当前的库存数量、进货日期等。
   - **模型关系**:
     - `Product` 拥有一个 `Stock`。
     - `Stock` 属于一个 `Product`。
   - **示例**:
     ```ruby
     class Product < ApplicationRecord
       has_one :stock, dependent: :destroy
     end

     class Stock < ApplicationRecord
       belongs_to :product
     end
     ```

### 8. **租房和租约(RentalProperty 和 LeaseAgreement)**
   - **场景**:每个租房只有一个对应的租约,记录租客的合同细节。
   - **模型关系**:
     - `RentalProperty` 拥有一个 `LeaseAgreement`。
     - `LeaseAgreement` 属于一个 `RentalProperty`。
   - **示例**:
     ```ruby
     class RentalProperty < ApplicationRecord
       has_one :lease_agreement, dependent: :destroy
     end

     class LeaseAgreement < ApplicationRecord
       belongs_to :rental_property
     end
     ```

### 总结:
一对一关联通常用于确保两个对象之间的唯一性和紧密关联。例如,用户和个人资料、供应商和账户、订单和发票等场景中,需要确保每一方都只有一个对应的记录,且彼此紧密关联。这种设计可以帮助简化数据结构,增强数据完整性,并且可以确保业务逻辑的一致性。
rails belongs_to has_one