belongs_to belongs_to association only only has_many或has_one
你能在Rails中拥有belongs_to
belongs_to
关系吗?
搜索 结果给了我两个结果。 事实上我找不到关于这个主题的非常多的信息,这似乎表明它不应该被做或者是不好的做法。
我昨天问了一个关于a_many关系的问题,但是因为我找不到相关的信息,我会生成一个问题,以便人们在将来更容易搜索这个问题。 我正在解释另一个用户的答案(我希望这没关系)。
鞋子可以有很多袜子,但只有一个活跃的袜子。 其他袜子不活跃。 所有袜子都是独一无二的独特图案。 我想确保我没有相同图案的袜子。 我想我可以这三种方式做到这一点
class Sock < ActiveRecord::Base belongs_to :shoe end
要确定袜子是活动还是非活动,请给它的’所有者鞋提供对其活动袜子的引用,如下所示:
class Shoe < ActiveRecord::Base belongs_to :sock end
去它的主人Shoe并检查Shoe的活动袜子是否是当前的袜子。 例如
def is_active owner_shoe.active_sock == self
将它们与外键相关联
class CreateGettingDressed < ActiveRecord::Migration def change create_table :shoes do |t| t.belongs_to :active_sock, foreign_key: "sock_id" t.string :size t.timestamps null: false end create_table :socks do |t| t.belongs :owner_shoe, foreign_key: "shoe_id" t.string :pattern end end end
你遇到的问题是你的两个function是冲突的:
Shoe
可以有很多Socks
,但只有一个活跃的Sock
您希望将两个模型关联到两个不同的关联。 虽然这样做很简单,但我觉得你尝试做的方式有点受限制。
这是我如何设置基本关联:
#app/models/sock.rb class Sock < ActiveRecord::Base #columns id | shoe_id | name | active (boolean) | created_at | updated_at belongs_to :shoe end #app/models/shoe.rb class Shoe < ActiveRecord::Base #columns id | name | etc | created_at | updated_at has_many :socks scope :active, -> { where(active: true).first } end
这将使您能够调用:
@shoe = Shoe.find 1 @shoe.socks.active #-> first sock with "active" boolean as true
它还会否定包含active?
的需要active?
sock
模型中的方法。 你可以打电话给@shoe.socks.find(2).active?
得到关于它是否有效的回应。
现在,这应该适用于基本function。
但是,你提到了几个扩展:
如果袜子
active
或inactive
我想确保我没有相同图案的袜子
这增加了我用join
模型解决的额外规范( has_many :through
):
#app/models/sock.rb class Sock < ActiveRecord::Base has_many :shoe_socks has_many :shoes, through: :shoe_socks end #app/models/shoe_sock.rb class ShoeSock < ActiveRecord::Base # columns id | shoe_id | sock_id | pattern_id | active | created_at | updated_at belongs_to :shoe belongs_to :sock belongs_to :pattern end #app/models/shoe.rb class Shoe < ActiveRecord::Base has_many :shoe_socks has_many :socks, through: :shoe_socks, extend: ActiveSock scope :active, -> { where(active: true).first } end
您可以在此处阅读以下代码的更多信息:
#app/models/concerns/active_sock.rb module ActiveSock #Load def load captions.each do |caption| proxy_association.target << active end end #Private private #Captions def captions return_array = [] through_collection.each_with_index do |through,i| associate = through.send(reflection_name) associate.assign_attributes({active: items[i]}) return_array.concat Array.new(1).fill( associate ) end return_array end ####################### # Variables # ####################### #Association def reflection_name proxy_association.source_reflection.name end #Foreign Key def through_source_key proxy_association.reflection.source_reflection.foreign_key end #Primary Key def through_primary_key proxy_association.reflection.through_reflection.active_record_primary_key end #Through Name def through_name proxy_association.reflection.through_reflection.name end #Through def through_collection proxy_association.owner.send through_name end #Captions def items through_collection.map(&:active) end #Target def target_collection #load_target proxy_association.target end
此设置基本上将所有“逻辑”放入连接模型中。 IE你将拥有一个袜子数据库,一个鞋子和一个连接数据库,两者都有。
这仍然允许您调用@shoe.socks.active
但不必降低数据模型中的数据完整性。
我还添加了一些我后来编写的代码 - 这使您能够从连接模型中访问属性。 它使用ActiveRecord中的proxy_association
对象,因此它不再调用SQL。
这个添加的代码会追加active?
属性为任何关联的Sock
对象。
在Rails中, belongs_to
是模型具有外键的指示符。 例如,如果袜子belongs_to
鞋子,那么你的袜子桌子将有一个shoe_id
字段。 有许多协会可供你使用,但同时使用鞋子和袜子belongs_to
不必要的复杂声音。
最直接的解决方案是稍微改变语言,并认为每个袜子都有一个活跃的鞋子。 这样,如果你将袜子换到另一只鞋子,那么你就没有任何东西来整理鞋子了。 您的数据更有可能保持一致。
class Shoe < ActiveRecord::Base has_one :sock end class Sock < ActiveRecord::Base belongs_to :shoe end
你现在可以叫shoe.sock
来买一双鞋的活动袜子,或者sock.shoe
来买袜子的鞋子。
或者,也许你希望每双鞋都有一个专用的袜子池。 我们可以扩展我们以前的解决方案以支持这一点,将我们的关系命名为active_sock
以使事情变得更清晰,并使用validation器来确保我们的袜子来自池:
class Shoe < ActiveRecord::Base has_many :socks has_one :active_sock, class_name: "Sock", foreign_key: "active_shoe_id" validates :active_sock_id, inclusion: { in: sock_ids } end class Sock < ActiveRecord::Base belongs_to :shoe def active? shoe.active_sock == self end end
现在你可以给shoe.socks
打电话来获得所有可用的袜子,鞋子和shoe.active_sock
来获得活跃的袜子。 从袜子那边,然后sock.shoe
返回哪个鞋“拥有”这个袜子,并袜子sock.active?
返回此袜子当前是否有效。