捕获正确的模型行为,我使用serialize()还是模型关系?

时间:2009-09-08 19:02:54

标签: ruby-on-rails ruby

我有一个名为网站的模型。一个站点将有几个相邻的站点(也是其他站点的相邻站点)。

我正在尝试确定如何最好地捕获邻接列表。

我考虑过在站点模型中创建一个文本字段,并使用serialize来存储/检索所有相邻站点的数组。这样做的问题是我违反DRY,因为相邻站点之间没有形成真正的关系,因此必须单独存储每个站点的相邻站点列表。

我开始挖掘has_and_belongs_to_many关系的一些在线文档,但在示例中我发现这种关系似乎总是在两种不同类型的对象之间。我可以与同一个对象建立has_and_belongs_to_many关系吗?

这样:

class Site < ActiveRecord::Base  
    has_and_belongs_to :sites
end

或者我是否需要为相邻网站创建单独的表格?

4 个答案:

答案 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语句)。