rails: 一对多关联(belongs_to/has_one)
例如,如果应用程序中的每个供应商只有一个帐户,则可以像这样声明供应商模型:
01 创建 Supplier 和 Account 模型
你需要给 Account
模型添加 supplier_id
外键,以建立一对一的关联。
运行以下命令来生成 Supplier
和 Account
模型:
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
```
### 总结:
一对一关联通常用于确保两个对象之间的唯一性和紧密关联。例如,用户和个人资料、供应商和账户、订单和发票等场景中,需要确保每一方都只有一个对应的记录,且彼此紧密关联。这种设计可以帮助简化数据结构,增强数据完整性,并且可以确保业务逻辑的一致性。