2014-12-15 5 views
4

В моем приложении город может иметь много ссылок. Ссылка соединяет два города вместе и двунаправлена, поэтому ссылка не имеет «от» и «до». Это приводит к следующему db schema:has_many отношение с двумя внешними ключами

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.endpoint1, и city.endpoint2.

Есть ли более элегантные решения для определения отношения has_many с двумя внешними ключами? Или я должен уйти от этого подхода и как-то изменить свой db schema?

+0

Вы можете переписать первую строку своего вопроса? Вы хотите, чтобы в городе было много ссылок, а также было соединение по городу и городу? – kirqe

+0

Возможно, вы могли бы работать с наборами 'has_many', например' has_many: links_to' и 'has_many: links_from'. И затем больше или меньше делаете то, что делаете сейчас? – Albin

ответ

-1

Я думаю, что это та же проблема, что и «дружба» в подобных facebook-приложениях, где один пользователь следует за другим, и они оба следуют друг за другом, они друзья. У меня было это раньше, и я решил это, присоединившись к таблице «Друзья» против себя, что обеспечило бы взаимную дружбу. Разница здесь в том, что соединения всегда присутствуют независимо от направлений, но в целом я вижу ту же проблему, с которой я столкнулся раньше. Мое предложение было бы:

  1. При создании ссылок, всегда создавать их bothways, 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 
    

Это решение может быть не оптимальным для этой проблемы, но это определенно более гибко, так как оно также позволит вам обрабатывать однонаправленные соединения одинаково.

Смежные вопросы