Rails - polimorf világ

Azért vannak dolgok, amikkel lehet szépeket szívni.

A feladat valami olyasmi volt, hogy kell egy újrafelhasználható “cím” osztály, ami külön táblára is képeződne le, hogy ne a megfelelő táblákat terheljük feleslegesen, plusz a címek amúgy se mindig kellenek pl. a felhasználókezeléshez. Azért kell újrafelhasználhatónak lennie, mert két különböző dolog is használ címeket a rendszerben.

Nem akarom nagyon húzni az időt, az alábbi kód született rá:

Polimophic user profile
1
2
3
4
5
6
7
8
9
class Address < ActiveRecord::Base
  belongs_to :addressable, :polymorphic => true
end

class User < ActiveRecord::Base
  has_many  :addresses, :as => :addressable
  has_one   :billing_address , :as => :addressable, :class_name => 'Address', :conditions => { :billable => true, :shippable => false }
  has_one   :shipping_address, :as => :addressable, :class_name => 'Address', :conditions => { :shippable => true, :billable => false }
end

Erre kedves barátom azt mondaná, hogy szép baleset. És akkor még nagyon finoman fogalmazna. Nézzük, mik azok a buktatók, amin át lehet esni egy ilyet nézve:

  • A has_many asszociáció ugye azért kell, hogy legyen valami, ami polimorf. Elvben bele lehet suvasztani a has_one mellé is, de nekem egyébként is kell tudnom a címeket egyben lekérni, akkor meg miért ne emelném ki?
  • Az előbbi asszociáció alapján definiálunk két hozzárendelést. Ugye itt a hangsúly a :conditions hashen van, ez mondja meg, hogy a polimorf tömbből mely adatok kellenek (pontosabban, hogy az asszociáció alapján generált query-ben a WHERE feltétel hogyan bővüljön)
  • Az egyik trükk az, hogy mindenképp meg kell adni az osztályt is, ugyanis a has_one asszociáció nem kéri le ezt az infót a hivatkozott polimorf asszociációtól, hanem saját maga áll neki találgatni - természetesen rosszul.
  • A másik trükk pedig, hogy mivel ez egy kétparaméteres, egymást kölcsönösen kizáró feltétel, így mindkettőt meg kell adni, különben létrehozáskor előjöhet olyan csúfság, hogy valaki meghinteli a dupla false-t - vagyis úgy mentünk el pl. egy billing címet, hogy az elvész az :addresses tömb nevű fekete lyukban (van értelme amúgy a dupla false-nak is, csak abból nem billing meg shipping címek lesznek, hanem csak címek). Azaz, mentéskor a billing_address-en keresztül mentünk, de a mentés után a billing_address pont ugyanolyan nil lesz, mint előtte volt vala.

Azért ezzel is sikerült egy jó órát szívni…

Comments