你可以在Rails中建立belongs_to
belongs_to
关系吗?
Search results给了我两个结果。事实上我找不到关于这个问题的非常多的信息,这似乎表明它不应该被做或者是不好的做法。
我问过yesterday关于has_many的关系,但是因为我找不到相关的信息,我会生成一个问题,以便人们在将来更容易搜索。我正在解释另一个用户的回答(我希望没问题)。
鞋子可以有很多袜子,但只有一个活跃的袜子。其他袜子不活跃。所有袜子都是独一无二的独特图案。我想确保我没有相同图案的袜子。我想我可以这三种方式做到这一点
class Sock < ActiveRecord::Base
belongs_to :shoe
end
要确定袜子是处于活动状态还是非活动状态,请给它的'所有者鞋提供对其活动袜子的引用,如下所示:
class Shoe < ActiveRecord::Base
belongs_to :sock
end
去它的主人Shoe并检查Shoe的活动袜子是否是当前的袜子。 E.g。
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
答案 0 :(得分:4)
在Rails中,belongs_to
表示模型具有外键。例如,如果袜子belongs_to
是鞋子,那么你的袜子桌子将有一个shoe_id
字段。有a number of associations可供您使用,但同时使用belongs_to
鞋子和袜子听起来不必要复杂。
最直接的解决方案是稍微改变语言,并认为每个袜子都有一个活跃的鞋子。这样,如果你将袜子换成另一只鞋子,那么你就没有任何东西来整理鞋子了。您的数据更有可能保持这种方式一致。
class Shoe < ActiveRecord::Base
has_one :sock
end
class Sock < ActiveRecord::Base
belongs_to :shoe
end
现在,您可以拨打shoe.sock
以获得鞋子的活动袜子,或sock.shoe
来获得袜子的鞋子。
或者,也许您希望每只鞋都有专用的袜子。我们可以扩展我们以前的解决方案以支持这一点,命名我们的关系active_sock
以使事情更清楚,并使用验证器确保我们的袜子来自池:
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
返回哪个鞋子&#34;拥有&#34;这个袜子,sock.active?
返回此袜子当前是否有效。
答案 1 :(得分:1)
你遇到的问题是你的两个功能是冲突的:
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?
模型中包含sock
方法。您可以致电@shoe.socks.find(2).active?
以获得有关其是否有效的回复。
现在,这个 应该可以很好地运行基本功能。
但是,你提到了几个扩展:
如果袜子是
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
您可以详细了解以下代码here:
#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你将拥有一个 socks 的数据库,一个鞋和一个两者兼容的连接数据库。
这仍然允许您调用@shoe.socks.active
,但不必降低数据模型中的数据完整性。
我还添加了一些我后来编写的代码 - 这使您能够从连接模型中访问属性。它使用ActiveRecord中的proxy_association
对象,因此它不再调用SQL。
此添加的代码会将active?
属性附加到任何关联的Sock
对象。