我有一个名为网站的模型。一个站点将有几个相邻的站点(也是其他站点的相邻站点)。
我正在尝试确定如何最好地捕获邻接列表。
我考虑过在站点模型中创建一个文本字段,并使用serialize来存储/检索所有相邻站点的数组。这样做的问题是我违反DRY,因为相邻站点之间没有形成真正的关系,因此必须单独存储每个站点的相邻站点列表。
我开始挖掘has_and_belongs_to_many
关系的一些在线文档,但在示例中我发现这种关系似乎总是在两种不同类型的对象之间。我可以与同一个对象建立has_and_belongs_to_many
关系吗?
这样:
class Site < ActiveRecord::Base
has_and_belongs_to :sites
end
或者我是否需要为相邻网站创建单独的表格?
答案 0 :(得分:1)
请注意,您找到的解决方案仅适用于一个方向:
>> Site.last.friends
[]
>> Site.last.friends << Site.first
[#<Site id: 1, name: "First", description: "The First", created_at: "2009-09-08 21:15:09", updated_at: "2009-09-08 21:15:09">]
>> Site.last.friends
[#<Site id: 1, name: "First", description: "The First", created_at: "2009-09-08 21:15:09", updated_at: "2009-09-08 21:15:09">]
>> Site.first.friends
[]
如果您希望它以两种方式工作,您可以使用以下内容:
class Site < ActiveRecord::Base
has_and_belongs_to_many :l_adjacent_sites, :class_name => 'Site', :join_table => 'sites_sites', :foreign_key => 'l_site_id', :association_foreign_key => 'r_site_id'
has_and_belongs_to_many :r_adjacent_sites, :class_name => 'Site', :join_table => 'sites_sites', :foreign_key => 'r_site_id', :association_foreign_key => 'l_site_id'
end
但弧线指向:
>> Site.first.r_adjacent_sites
[]
>> Site.last.r_adjacent_sites < Site.first
[#<Site id: 1, name: "First", description: "The First", created_at: "2009-09-08 21:15:09", updated_at: "2009-09-08 21:15:09">]
>> Site.last.r_adjacent_sites
[#<Site id: 1, name: "First", description: "The First", created_at: "2009-09-08 21:15:09", updated_at: "2009-09-08 21:15:09">]
>> Site.first.l_adjacent_sites
[#<Site id: 4, name: "Fourth", description: "The fourth", created_at: "2009-09-08 21:48:04", updated_at: "2009-09-08 21:48:04">]
如果你想要代表的是有针对性的弧线,你会没事的;我还没有找到非导向弧的解决方案(除了mysite.l_adjacent_sites + mysyte.r_adjacent_sites]
)。
修改强>
我试图破解某些东西以获得adjacent_sites
named_scope
之类的东西,但找不到任何东西;另外,我不确定是否存在一般解决方案(允许您过滤添加更多条件的结果)。
由于执行l_adjacent_sites + r_adjacent_sites
强制执行(两个)查询,
我只能提出类似的建议:
def adjacent_sites options={}
l_adjacent_sites.all(options) + r_adjacent_sites.all(options)
end
这应该允许你做以下事情:
@mysite.adjacent_sites :conditions => ["name LIKE ?", "f%"]
但仍有问题:
排序不起作用,也就是说,您将得到一个半分组,例如[1, 3, 5, 2, 4, 6]
。如果你需要对结果进行排序;你必须在红宝石中做到这一点。
限制只有一半工作::limit => 1
最多可以提供2个结果,因为会执行两个查询。
但我很肯定,在大多数情况下,你会没事的。
答案 1 :(得分:0)
应该可以这样做,但是它将涉及到玩
上的选项has_and_belongs_to_many
你可能有一个连接表定义了一个迁移的东西:
create_table :sites_associated_sites, :id => false do |t|
t.integer :site_id
t.integer :associated_site_id
end
然后在模型中你需要设置has_and_belongs_to_many两次
class Site < ActiveRecord::Base
has_and_belongs_to_many :sites, :join_table => 'sites_associated_sites'
has_and_belongs_to_many :associated_sites, :class_name => 'Site',
:join_table => 'sites_associated_sites'
end
这个答案应该用一点点盐,因为这比其他任何东西都更响亮,但绝对值得阅读API中的has_and_belongs_to_many方法:http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001836
答案 2 :(得分:0)
我挖了一些,为此找到了一个很好的资源。他们使用的示例是,如果您有一类用户,并且用户可以拥有也是用户的朋友,但您不想创建单独的朋友表。
该文章的作者所做的是创建一个只包含外键的连接表,它允许habtm关系在没有第三个表的情况下存在。
这是链接:
http://www.urbanpuddle.com/articles/2007/06/14/rails-mini-tutorial-user-habtm-friends
答案 3 :(得分:0)
在参考书 The Rails Way (第227页)中,进行了一些额外挖掘,找到了实现Bidrectional Relationships的方法。不幸的是,文中的解决方案存在两个问题。首先它是不完整的,虽然在本书的错误跟踪器/勘误表页面上有完整的版本
class BillingCode < ActiveRecord::Base
has_and_belongs_to_many :related,
:join_table => 'related_billing_codes',
:foreign_key => 'first_billing_code_id',
:association_foreign_key = 'second_billing_code_id',
:class_name => 'BillingCode',
:insert_sql => 'INSERT INTO related_billing_codes (`first_billing_code_id`, `second_billing_code_id`) VALUES (#{id}, #{record.id}), (#{record.id}, #{id})',
:delete_sql => 'DELETE FROM related_billing_codes WHERE (`first_billing_code_id` = #{id} AND `second_billing_code_id` = #{record.id}) OR (`first_billing_code_id` = #{record.id} AND `second_billing_code_id` = #{id})'
end
第二个问题是默认开发数据库SQLite3不支持解决方案(依赖于在同一 INSERT 语句中将两条记录插入表中的SQL语句)。