Trudniejsza relacja w modelu

mam taki problem:
Mam model Word, który przechowuje mi informacje o jakimś tam słowie kluczowym
Chciałbym utworzyć relację wiele do wielu:

    • między jednym słowem a drugim
      czyli pewnie byłaby tu jakaś tabela typu word_word z polami word1, word2
      Chciałbym mieć teraz dostęp z poziomu słowa do wszystkich słów z którymi dane słowo jest w relacji: word.next_words
      oraz wszystkie słowa, które są w relacji z danym słowem: word.prev_words
    • między trzema słowami
      tutaj bardziej skomplikowane i w sumie nie wiem jak to mogłoby być obsługiwane.
      Generalnie chciałbym mieć uporządkowane trójki słów i potem móc wyszukiwać trzeciego słowa na podstawie dwóch słów początkowych.
      Wiem, że mogę to zrobić w zwykłej tablicy z trzema polami i wszystko obsługiwać samemu, ale czy nie ma sposobu żeby jakoś to ułatwić?

To co opisujesz nie jest trywialne ale do zrobienia, generalnie uznaję że jest to graf skierowany (zresztą tak to wynika z opisu), dla grafu nie skierowanego rozwiązanie jest odrobinę trudniejsze.

Pola id, word

class Word < ActiveRecord::Base
has_many :next_word_relations, :foreign_key => ‘source_word_id’
has_many :next_words, :class_name => “Word”, :through => :next_word_relations

has_many :prev_word_relations, :foreign_key => ‘destination_word_id’
has_many :prev_words, :class_name => “Word”, :through => :prev_word_relations

Ad 2) Wyszukuje wszystkie słowa które posiadają jako źródła wszystkie słowa jakie podasz w parametrze (rozwiązanie ogólne - zadziała bez problemu w każdej bazie danych obsługującej dobrze podzapytania - czyli postgresql, oracle, db2, i zdaje się najnowsze mysqle)

def self.find_by_related(words)
scoped(:select => ‘words.’, :from => ‘words’, :conditions => [’ (SELECT COUNT() FROM word_relations WHERE word_relations.source_word_id = IN (?) AND word_relations.destination_word_id = words.id) >= ?’, words.map(&:id), words.length])
end
end

Pola: source_word_id, destination_word_id

class WordRelation < ActiveRecord::Bae
belongs_to :source_word, :class_name => “Word”, :foreign_key => “source_word_id”
belongs_to :destination_word, :class_name => “Word”, :foreign_key => “destination_word_id”
end

Odnośnie punktu 1 )

Z czego wynika next i prev word ? Użytkownik ustala kolejność między nimi czy z alfabetu ?
Czy relacja jest symetryczna?

a.next_word.prev_word == a ?

Mógłbyś trzymać w tabeli kolumny previous_word i next_word. Wtedy jest to banalnie prosty select.

Właśnie zauważyłem, że Świstak dokładnie to opisał.

Odnośnie przykładu 2)

Co jest skomplikowanego w TripleWord.find_by_first_word_and_second_word(‘ala’, ‘ma’).try(:third_word) => ‘kota’ ?

Możesz użyć MongoDB - w dokumencie można trzymać tablicę i pytać o nią na różne sposoby.
1)

[code=Javascript]db.relations.insert({words: [‘foo’, ‘bar’]})
db.relations.insert({words: [‘baz’, ‘foo’]})

// Dokumenty zawierające foo
db.relations.find({words: ‘foo’})[/code]
2)

[code=Javascript]db.sentences.insert({words: [‘foo’, ‘bar’, ‘baz’]})

// Dokumenty zawierające foo jako pierwszy element i bar jak drugi:
db.sentences.find({‘words.0’: ‘foo’, ‘words.1’: ‘bar’})

// Dokumenty zawierające co najmniej foo i bar:
db.sentences.find({words: {$all: [‘foo’, ‘bar’]}})[/code]