Relacja belongs_to i has_one

Witam serdecznie, zastanawia mnie realizacja pewnego powiązania. Przypadek pewnie banalny, ale mam z nim problem. Przypuśćmy, że mamy klasę “wzrok” (z atrybutem stan), która ma się wiązać z klasą “oko” (z atrybutem np. dioptria). Jak stworzyć powiązanie zakładając, że wzrok (Sight) będzie miał z Eye relację 1:2 (choć smutne przypadki z 1:1 też mogą się zdarzyć, wtedy jedno oko będzie miało nil)? Próbowałem w stylu:

class Sight < ActiveRecord::Base
   belongs_to :eye_left, class_name: 'Eye'
   belongs_to :eye_right, class_name: 'Eye'
end

class Eye < ActiveRecord::Base
end

Problem jednak jest taki, że belongs_to raczej średnio pasuje do klasy Sight, a drugi to, że w Eye nie mam żadnych powiązań.

Myślałem również nad stworzeniem klasy pośredniej typu:

class SightEye < ActiveRecord::Base
   belongs_to :sight
   belongs_to :left_eye, class_name: 'Eye'
   belongs_to :left_eye, class_name: 'Eye'
end

i wtedy

class Sight < ActiveRecord::Base
   has_one :sight_eye
end

class Eye < ActiveRecord::Base
   belongs_to :sight
end

ale to również nieciekawie wygląda. Jakieś pomysły?

A ta relacja jest naprawdę potrzebna? Sight może mieć zwyczajnie atrybuty dla lewego i prawego oka w swojej tabeli. Wtedy każdy rząd będzie dotyczył jednego pacjenta. Ewentualnie możesz stworzyć relacje Sight has many Sight::Dioptria, żeby wzrok mógł mieć wiele atrybutów, ale to trzeba rozważyć w kontekście potrzeb aplikacji.
Jeżeli mocno chcesz mieć każde oko w oddzielnej klasie możesz np. użyć


albo, jeszcze prościej, zrobić PORO czerpiące z obiektu Sight.

class Sight < ActiveRecord::Base
   has_one :eye_left, class_name: 'Eye'
   has_one :eye_right, class_name: 'Eye'
end

class Eye < ActiveRecord::Base
  belongs_to :sight
end

EDIT: To jest złe na tak wielu poziomach.

Dzięki @kham, myślałem, aby dioptrie wrzucić bezpośrednio do Sight i byłoby to pewnie ok, ale sprawa by się komplikowała, gdyby takich atrybutów było więcej (np. prócz dioptrii jeszcze kolor oka). O PORO i agregacjach będe musiał doczytać.

@ciastek niestety nie do końca:

s = Sight.find(1)
s.create_eye_right(dioptre: 3)
s.create_eye_left(dioptre: 5)
# do tej pory s.eye_right i s.eye_left działa dobrze
s = Sight.find(1)
# niestety teraz s.eye_left/right zwracają to samo oko (ostatnio stworzone)

Swoją drogą zastanawiam się dlaczego tak to działa.

A np.

    class Sight <  ActiveRecord::Base
  has_one :dioptre    
  delegate :left_eye, :right_eye, to: :dioptre, prefix: true
 end

class Dioptre < ActiveRecord::Base
  attr_accessible :left_eye, :right_eye
  belongs_to :sight
end

Teraz dokładasz kolor oczu przez dodanie has_one i znowu delegację z prefixem

Ok, dzięki @kham, nie wiem, czy to trochę nie overkill, ale przynajmniej już mam jakieś tropy.