Ulepszanie funkcjonalności Active Record

Opublikowane przez 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
end

Taki 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
end

Jednak 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_models

Po odpaleniu komendy

rake annotate_models

Ruby “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
end

W 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]]
end

Sytuację 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
end

moż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
end

ez_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
end

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

Tagi ,  | 4 comments

Comments

  1. Avatar lopex powiedział about 21 hours later:

    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

  2. Avatar dr_bonzo powiedział 3 days later:

    ‘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

  3. Avatar pak powiedział 3 days later:

    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

  4. Avatar Jarosław Zabiełło powiedział 9 days later:

    Ten Condition Builder to chyba też badziew. Jak tam zbudować warunek “field IS NOT NULL”?

(leave url/email »)

   Pomoc języka formatowania Obejrzyj komentarz