如果希望Account表关联上Member表,一个用户有多个钱包,建表的时候,
- 在数据库的accounts表上加上
user_id
的字段, - 在model/account.rb中,写上 belongs_to
:user
会通过belongs_to类宏自动生成以下完整版代码:
belongs_to: :user, class_name: 'User', foreign_key: :member_id, primary_key: :id
单向关联的好处:通过account.user.email
能获取钱包用户的邮箱,代码简洁可读性强
[!NOTE|label:member和member_id区分命名的好处] 访问外键Member通过
account.user
,获取外键ID通过account.user_id
,从命名上区分用途
如果在models/user.rb
中加上has_many: accounts
就能反过来通过user.accounts
查询用户拥有的钱包,account和user建立起双向关联,
user.accounts.map { |account|
{
names: account.name,
currencies: account.currency.name
}
}
上诉代码如果没有currency这行,遍历时只会查询一次Account表的内容
但是跨表查currency时会对Currency表进行N+1查询
解决方案:先建立所需关联,通过**includes(:currency)**干掉N+1查询
正确地建立关联+includes能将N个SQL转化为SELECT * FROM xxx WHERE id IN [...]
has_many和has_one
如果是一对一的关联,用has_one;否则用has_many
[!NOTE|label:has_one和has_many的区别] has_one使用单数形式,has_many使用复数形式且会返回一个数组
例如邮件记录表有俩字段sender_id和receiver_id
需要区分两个关联的名称,所以可以写成
belongs_to :sender, class_name: 'User'
Manager有多个Operation,每个Operation属于一个Manager,
但是Operation表的Manager外键不希望命名为manager_id,老板觉得可读性不行
那好吧,命名为operator_id如何?——不行,没有operators这个表,不要这样误导性命名
最后的命名方案: operator_member_id 或 operator_manager_id
!> 因为没按约定,所以要告诉rails外键名是operator_member_id
而不是manager_id
了
不遵守rails命名约定带来的麻烦是,belongs_to和has_many/one要指出外键名
belongs_to :manager, foreign_key:
'operator_member_id'
完整写法:
belongs_to :manager, class_name: 'Manager', foreign_key:
'operator_member_id'
,primary_key
: :id
还有一种情况,有两个字段的外键指向相同一个表,如发送人,接收人
belongs_to :sender, class_name: 'User' belongs_to :receiver, class_name: 'User'
写上这两句就能以xxx.sender_member.name
访问发件人的姓名
has_many through:
医生有多个病人,通过第三个表 预约记录,那么医生model中has_many 病人, through: 预约记录
多态关联
相关文章