在Rails中如何自定义has_many关联(含间接关联)的名称?
当然可以!在Rails里自定义has_many关联的名称非常灵活,不管是直接关联还是间接的has_many :through关联,都能轻松实现你的需求,下面给你详细说明:
一、直接has_many关联的自定义名称
假设你的Product模型原本关联State模型,默认用@product.states访问,现在要改成@product.states_where_it_is_sold,只需要在关联定义里加上class_name参数,明确指定对应的模型类即可:
class Product < ApplicationRecord # 自定义关联名称,通过class_name告诉Rails对应的模型是State has_many :states_where_it_is_sold, class_name: "State" end
这里的核心是class_name参数:因为Rails默认会根据关联名称(比如states)去推断对应的模型类(State),当你把关联名称改成非默认的states_where_it_is_sold时,必须手动指定模型类,否则Rails会找不到对应的表和模型。
定义完成后,你就可以用@product.states_where_it_is_sold来访问关联数据,和原来的@product.states功能完全一致。
二、间接has_many关联(has_many :through)的自定义名称
如果是通过中间模型的间接关联,同样可以自定义关联名称,甚至连中间关联的名称也能一起自定义。举个例子,假设Product通过ProductState中间模型关联State:
情况1:仅自定义最终关联名称
class Product < ApplicationRecord # 中间模型的关联用默认名称 has_many :product_states # 自定义最终关联名称,指定through指向中间关联,class_name指定目标模型 has_many :states_where_it_is_sold, through: :product_states, class_name: "State" end
情况2:同时自定义中间关联和最终关联名称
如果你想把中间关联的名称也改成更贴合业务的(比如sales_locations),可以这样写:
class Product < ApplicationRecord # 自定义中间关联名称,class_name指定中间模型 has_many :sales_locations, class_name: "ProductState" # 最终关联通过自定义的中间关联名称来关联 has_many :states_where_it_is_sold, through: :sales_locations, class_name: "State" end
额外提示:自定义外键(可选)
如果你的数据库中外键字段不是Rails默认的(比如不是product_id),还可以通过foreign_key参数指定:
has_many :states_where_it_is_sold, class_name: "State", foreign_key: "associated_product_id"
不过大部分情况下,遵循Rails的命名约定就不需要额外配置这个参数。
这样你就能完全按照业务逻辑来命名关联,让代码更易读易懂啦!
内容的提问来源于stack exchange,提问作者Augusto Carmo

