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
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ć.
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.
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