Bawiąc się ostatnio z RubyOnRails podczas pisania pewnego projektu trafiłem na bardzo dziwną przypadłość.
RubyOnRails jest wyposażony w mechanizm o nazwie ActiveRecord który jest odpowiedzialny za mapowanie obiektów użytkownika do bazy danych, ich wyszukiwanie, kasowanie, tworzenie i modyfikowanie.
Wśród wielu właściwości ActiveRecord umożliwia dziedziczenie obiektów z bazy danych. Przykładowo mamy obiekt Klient na bazie którego są zbudowane dwa inne obiekty: KlientKorporacyjny oraz KlientIndywidualny. Ponieważ większość baz danych nie jest w stanie obsłużyć czegoś takiego wprost, ActiveRecord musi wykonać troche “magii” żeby to zadziałało. Używa do specjalnej kolumny (domyślnie “type”) w której przechowuje nazwe klasy do której należy obiekt.
Dodatkową funkcjonalnością udostępnioną przez powyższy mechanizm, jest automatyczne dopisywanie:
where type='KlientKorporacyjny'
do SQL generowanego przez funkcję find. Oczywiście w momencie utworzenia nowego rekordu, jego typ także zostanie odpowiednio ustawiony.
Skuszony takimi oto urokami skorzystałem z takiego mechanizmu. Stworzyłem sobie następujące klasy:
class Category < ActiveRecord::Base
validates_uniqueness_of :name, :scope => :type
end
class ContentCategory < Category end
class WorkshopCategory < Category end
No i niestety przy próbie dodania czy zmodyfikowania rekordu pojawił się Exception. Po chwili grzebania doszedłem do tego że winny jest scope => :type. Nie wiem czym to jest spowodowane, ale type nie może być brany pod uwagę jako scope. Rozwiązaniem (mało eleganckim) okazało się dodanie nowej kolumny do Category o nazwie scope_helper i ustawianiu jej nazwy przez before_save.
Generalnie pomogło, natomiast pojawił się nowy problem. Chciałem dodać możliwość zmiany rodzaju kategorii z Workshop na Content i odwrotnie. Niestety przy tej konfiguracji poległem. Nie udało mi się w żaden sposób zmusić ActiveRecord do wykonania tej operacji. Po kilku godzinach walki dałem sobie spokój. Wyrzuciłem WorkshopCategory i ContentCategory, zastąpiłem je samym Category do którego dodałem kolumnę mytype które ustawiam ręcznie.
RubyOnRails ma wiele zalet i wygodnych rozwiązań - niestety czasem, kiedy chce się je wykorzystać trafia się na ograniczenia które mogą skutecznie zabrać pare godzin z harmonogramu.
Ciekaw jestem czy ktoś z Was także “wpadł” w jakąś pułapkę railsową ?