has_many与两个外键的关系

时间:2014-12-15 09:38:30

标签: ruby-on-rails

在我的应用中,一个城市可以有很多链接。链接将两个城市连接在一起并且是双向的,因此链接没有“从”和“到”。这导致以下db schema

  create_table "links", force: true do |t|
    t.integer "endpoint1_id"
    t.integer "endpoint2_id"
    t.integer "capacity"
  end

  create_table "cities", force: true do |t|
    t.string "name"
    t.string "lat"
    t.string "long"
  end

在我的ActiveRecord模型中,我想声明两个表之间的关系。因为我在设置has_many关系时似乎无法声明两个外键,所以我就这样解决了这个问题:

class City < ActiveRecord::Base    
  # has_many with two foreign keys?
  # has_many :links
  def links
    Link.where("endpoint1_id=? OR links.endpoint2_id=?", id, id)
  end    
end

class Link < ActiveRecord::Base
  belongs_to :endpoint1, :class_name => 'City'
  belongs_to :endpoint2, :class_name => 'City'
end

这允许我执行:City.find(1).links但似乎不是一个正确的解决方案,并且不强制执行任何继承。此外,从link我无法找到关系城市,除非我同时通过city.endpoint1city.endpoint2

是否有更优雅的解决方案来定义与两个外键的has_many关系?或者我是否可以放弃这种方法并以某种方式改变我的db schema

1 个答案:

答案 0 :(得分:-1)

我认为这与在类似Facebook的应用程序中的“友谊”是一样的问题,其中一个用户跟随另一个用户,并且他们都互相关注,他们是朋友。我之前有过这个,我通过加入友谊表来解决它,这将给予所有相互的友谊。这里的不同之处在于,无论方向如何,连接始终存在,但总的来说,我看到了之前遇到的同样问题。 我的建议是:

  1. 创建链接时,始终要创建它们, Link.new(endpoint1_id:city_1_id,endpoint2_id:city_2_id) Link.new(endpoint2_id:city_1_id,endpoint1_id:city_2_id)

  2. 然后从一个城市的连接中搜索时,从城市和链接中选择一个sql语句,如下所示:

    def connections # find your cities, where connections run both ways
    City.find_by_sql "
    select * from cities
      where id in
        (select f2.endpoint1_id from links as f1 inner join links as f2 on (f1.endpoint1_id = f2.endpoint2_id) and (f1.endpoint2_id = f2.endpoint1_id) and (f1.endpoint1_id = #{id.to_i}))" # normally this can cause an sql injection, but here it is handled by to_i
    end
    
  3. 此解决方案可能不是此问题的最佳解决方案,但它肯定更灵活,因为它还允许您以相同的方式处理单向连接。