Ulepszanie funkcjonalności Active Record
Posted by Jarosław Zabiełło Sun, 24 Jun 2007 12:19:00 GMT
Active Record to standardowy ORM używany przez framework Rails. Zasadniczo jest dobrze zaprojektowany, prosty i wygodny. Nie trzeba żmudnie definiować każdego pola w tabeli dla modelu, oraz można bez problemu podpinać aplikację do kilku różnych baz (czego np. nie ma Django).
Gdzie są te pola?
Kwestia tego, czy w modelu definiować pola czy nie, jest w zasadzie kontrowersyjna. Choć wadą jest dodatkowy nakład pracy związany ze żmudnym definiowaniem każdego pola, to zaletą jest to, że wystarczy spojrzeć na kod modelu, aby od razu wiedzieć z jakimi polami mamy do czynienia. W AR cała podstawowa definicja modelu sprowadza się (pomijam walidacje i relacje) do trywialnego zapisu:
class Person < ActiveRecord::Base
endTaki zapis zakłada, że istnieje tabela o nazwie people i posiada klucz główny o nazwie id. Jest to zgodne z konwencjami jakie przyjęto w Railsach i oczywiście można to zmienić jeśli jest taka potrzeba.
class Person < ActiveRecord::Base
self.table_name = :users
self.primary_key = :user_id
endJednak przy dużej ilości modeli nie zawsze będziemy pamiętać z jakimi polami w tabeli mamy do czynienia. Z pomocą przychodzi plugin Annotate Models. Po zainstalowaniu za pomocą komendy (odpalanej w katalogu aplikacji Rails) możemy trochę poprawić definicję modelu.
script/plugin install http://svn.pragprog.com/Public/plugins/annotate_modelsPo odpaleniu komendy
rake annotate_modelsRuby “automagicznie” przejrzy zawartość tabeli odpowiadającej każdemu modelowi ORM i doda odpowiednie komentarze do początku pliku. Np.
# == Schema Information
#
# Table name: news
#
# id :integer(11) not null, primary key
# header :text
# message :text
# updated_at :timestamp not null
#
class News < ActiveRecord::Base
endW efekcie mamy i prostotę i potrzebną nam informację w jednym miejscu.
Nietypowe tabele – złożone klucze główne
Nie jest tajemnicą, że AR nie posiada wsparcia dla złożonych kluczy głównych. Czy to znaczy, że Rails nie nadaje się do pracy z tabelami które takie klucze posiadają? Nie. To, że AR nie posiada takiej możliwości standardowo nic nie znaczy. Wystarczy doinstalować Composite Primary Keys który rozszerza standardowe możliwości AR. Z doświadczenia mogę potwierdzić, że działa całkiem dobrze. Jedyny problem jaki napotkałem dotyczył tworzenia dynamicznego rusztowania (scaffolding) w modelu posiadającym złożone klucze główne.
ez_where – bardziej obiektowe warunki wyszukiwania
AR jest krytykowany za zbyt dużą ilość kodu SQL jaki trzeba używać w warunkach. Np.
def find_users
find :all,
:conditions => ["name NOT LIKE ? AND rights IN(?)", 'kowalski', [1,4,8]]
endSytuację poprawia plugin ez_where. Aby jednak stosowanie jego było bardziej eleganckie, warto modyfikować (otworzyć) klasę ActiveRecord:Base. Po dodaniu następującego kodu do config/environment.rb:
class ActiveRecord::Base
def self.orm_conditions(&block)
Caboose::EZ::Condition.new(&block).to_sql
end
endmożna w modelu stosować wygodniejszy zapis warunków wyszukiwania.
def find_users
find :all,
:conditions => orm_conditions do
name! =~ 'kowalski'
rights === [1,4,8]
end
endez_where pozwala oczywiście na bardziej skomplikowane konstrukcje. (Poza tym pluginem istnieje podobny, konkurencyjny – Condition Builder, którego można zintegrować z AR w podobny sposób).
Appendix 2007-07-04
ez_where Ma już zdefiniowaną metodę c, więc powyższy przykład można zapisać:
def find_users
find :all,
:conditions => c do
name! =~ 'kowalski'
rights === [1,4,8]
end.to_sql
endTo nie jest wszystko o co można rozszerzyć AR. Istnieje już całkiem imponująca liczba pluginów które są w stanie uzupełnić AR o funkcjonalności jakich standardowo nie posiada. Jest to zgodne z polityką jaką twórcy Rails mają w tej dziedzinie. Rdzeń Railsów powinien być prosty i funkcjonalny do większości zastosowań. A dla osób potrzebujących dodatkowych możliwości, przewidziano mechanizm pluginów.


Kanały IRC![[Dilber w Onecie]](/images/larry.png)


Nie zapominajmy też o http://magicmodels.rubyforge.org/ drnick’a http://www.drnicwilliams.com/ pozwalające np: na użycie złożonych kluczy czy autokonfigurację relacji
‘annotate_models’ musze sprawdzic, bo do tej pory otwieralem plik migracji w malym okienku (no i za to lubie eclipse, mozna pootwierac wiele Edytorow jednoczesnie, a w Netbinsie slabo mi ro wychodzi, o ile sie tak da :)); a czy te komentarze sa updatowane po wykonaniu rake db:migrate? hmmmm chociaz to jest proste do zaimplementowania :D dwa taski. dobranoc
Condition Builder jest jak dlamnie idealny, bardzo prosty i w miare czytelny, nie korzysta z instance_eval wiec mam dostep do wszystkich zmiennych. Niestety wlasnie natknolem sie w nim na powazny blad.
Ten kod http://pastebin.4programmers.net/2714 Powinine miec operatory logiczne OR, natomista wygenerowany sql zawiera tylko same AND
Ten Condition Builder to chyba też badziew. Jak tam zbudować warunek “field IS NOT NULL”?