Merb - źródła informacji

Opublikowane przez Jarosław Zabiełło Fri, 12 Dec 2008 15:55:00 GMT

Od czasu wyjścia Merb 1.0 przybywa coraz więcej dobrych materiałów n/t tego frameworka (koledzy od Pylons, ktorzy od wieków tkwią w tej swojej wersji 0.9.x mogliby to sobie wziąć do serca). Przede pojawia się coraz więcej zapowiedzi książek…

Czytaj dalej...

Tagi , , , , , ,  | 13 comments

Wściekły Zed i dyskusja wokół Rubiego i Railsów

Opublikowane przez Jarosław Zabiełło Sun, 06 Jan 2008 22:49:00 GMT

Ostatnio jest trochę szumie w branży po bezpardonowym (i niewybrednym) ataku Zeda Shaw uderzającym w kilka znanych postaci z kręgów Rubiego i Rails. Pewnie nikt by na to nie zwrócił uwagi gdyby nie to, że Zed jest autorem znanego projektu Mongrel. Choć wpis się źle czyta (bo jest rozwlekły i niepotrzebnie przeplatany ciągłymi przekleństwami autora) to zwrócił uwagę na kilka istotnych problemów.

Czytaj dalej...

Tagi , , , , , , , , ,  | 17 comments

Sequel vs Active Record. Część 2 - integracja Rails z Sequelem

Opublikowane przez Jarosław Zabiełło Fri, 21 Dec 2007 12:27:00 GMT

W pierwszej części trochę wypunktowałem słabe strony standardowego ORM’a używanego w Railsach. Najlepiej zastąpić go szybszym i ogólnie dużo lepszym Sequelem. Można to zrobić na kilka sposobów: całkowicie zastąpić Active Record lub używać Sequela obok Active Record – jak kto woli.

Czytaj dalej...

Tagi , ,  | 6 comments

Szybki start z Rails, Merb i Pylons

Opublikowane przez Jarosław Zabiełło Sun, 16 Dec 2007 06:31:00 GMT

Celem tego tekstu jest porównanie podstawowych czynności niezbędnych do tego aby uruchomić Rails, Merb oraz Pylons. Zakładam że używany będzie

Czytaj dalej...

Tagi , , , , , , , ,  | 15 comments

Sequel vs Active Record. Część 1 - słabości AR.

Opublikowane przez Jarosław Zabiełło Wed, 12 Dec 2007 23:37:00 GMT

Gdy framework Ruby on Rails (dalej: RoR lub Rails) rozpoczynał swoją błyskotliwą karierę, zachwycał wszystkich prostotą i elegancją konstrukcji. Jednym z fundamentalnych modułów Railsów jest Active Record, biblioteka realizująca symulację wirtualnej bazy obiektowej, pozwalającą na pracę z relacyjnymi bazami danych za pomocą obiektów języka Ruby. Active Record (dalej AR) nie uniknął jednak kilku potknięć projektowych.

Czytaj dalej...

Tagi , , ,  | 5 comments

Ulepszony String i sprawa parametrów

Opublikowane przez Jarosław Zabiełło Fri, 29 Jun 2007 00:42:00 GMT

Ruby posiada bardzo bogate możliwości przetwarzania tekstu. Zasugerowany składnią Active Record i wcześniejszym doświadczeniem z Pythonem trochę się zdziwiłem, że Matz nie zaimplementował przekazywania hasza do operatora %.

Czytaj dalej...

Tagi , , ,  | 6 comments

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

Czytaj dalej...

Tagi ,  | 4 comments

Elastyczność Railsów

Opublikowane przez Jarosław Zabiełło Wed, 04 Oct 2006 15:01:00 GMT

Większość osób, które zetknęły się z frameworkiem Ruby on Rails zauważyła, że domyślne ustawienia są tam tak dobrane, aby maksymalnie uprościć i zminimalizować ilość ręcznej pracy przy ustawieniach. Jeśli więc ktoś trzyma się flozofii i konwencji nazw (np. dla tabel i ich pól) będzie miał znacznie mniej dodatkowej roboty z konfiguracją frameworka do pracy. Typowa definicja modelu wyglądać może nawet tak prosto:

class User < ActiveRecord::Base
end

Powyższa definicja zakłada, że tabela w bazie nosi nazwę “users”, a jej primary key nazywa się “id”. W przeciwieństwie do innych ORM’ów, railsowy ActiveRecord nie wymaga żadnego wcześniejszego definiowania pól. Ruby bez problemu sam sobie wyciagnie wszystkie nazwy pól w sposób dynamiczny wtedy, kiedy będzie mu to potrzebne.

Nietypowe struktury

Niestety, nie zawsze jesteśmy w takiej komfortowej sytuacji, że mamy wpływ na nazewnictwo tabel i ich pól. Jednak to nie jest większym problemem, bo Rails sobie z tym radzi równie prosto.

class User < ActiveRecord::Base
  set_table_name 'uzytkownicy'
  set_primary_key 'IdUzytkownika'
end

Jak widać, dużo pracy nam nie przybyło. W tym wypadku musieliśmy tylko jawnie podać jak się nazywa nasza tabela i jak się nazywa jej klucz główny.

Korzystanie z wielu baz

W momencie tworzenia projektu aplikacji RoR generowany jest automatycznie plik konfiguracyjny zawierający połączenie do bazy danych. Przykładowy plik config/database.yml mogłby wyglądać np. tak:

default: &defaults
  adapter: mysql
  host: localhost
  encoding: utf8
  username: jakis_login
  password: jakies_haslo

development:
  database: bookstore_dev
  <<: *defaults

test:
  database: bookstore_test
  port: 3307
  <<: *defaults

production:
  database: bookstore
  socket: /var/run/mysqld/mysqld.sock
  <<: *defaults

Co robi powyższy kod? Definiuje 3 bazy: produkcyjną, roboczą i testową. (Ta ostatnia jest używana tylko do testów jednostkowych więc nie powinno się tam wstawiać żadnych istotnych danych) W w/w konfiguracji zdecydowaliśmy, że wszystkie bazy będą korzystać z MySQL >=4.1 z ustawionym wew. kodowaniem UTF-8 (zalecane). Baza produkcyjna działać będzie na Linuksie, więc zamiast portu TCP, podano uniksowy socket. Baza testowa działa na porcie 3307, a robocza na domyślnym (3306). Główna sekcja “defaults” jest wspólna dla wszystkich trzech baz zgodnie z zasadą DRY (Don’t Repeat Yourself).

Załóżmy jednak, że chcemy korzystać z dodatkowej bazy i chcemy aby z niej korzystały niektóre modele. Żaden problem. Do pliku dopisujemy tylko dodatkową definicję połączenia do innej bazy:

other:
  adapter: mysql
  host: 192.168.0.123
  database: customers
  <<: *defaults

Jak widać, możemy tą metodą tworzyć aplikację korzystającą z rozproszonych baz. (W tym wypadku baza customers leży na zupełnie innym serwerze, ale korzysta z tego samego usera i hasła.)

No dobrze, ale jak modele mają rozpoznać z jakiego połączenia korzystają? To też prosta sprawa. Domyślnym połączeniem jest to, co zdefiniowano w sekcji domyślnej. Jedynie modele, które korzystają z innego połączenia, muszą to mieć jawnie zadeklarowane w definicji, np.

class Client
  establish_connection :other
end

Model Client oraz wszystkie modele utworzone z niego na drodze dziedziczenia, będą korzystać z innego połączenia niż domyślne.

BTW, to jedna z bardziej brakujących mi cech we frameworku Django (Pylons nie ma z tym żadnego problemu). Mam nadzieję, że wkrótce to poprawią i w Django będzie można bez problemu korzystać z wielu baz.

Wspolne modele dla wielu aplikacji Rails

W tym scenariuszu mamy za zadanie stworzyć szereg aplikacji webowych korzystających z oddzielnych baz o tej samej strukturze tabel. Chcemy uniknąć powielania kodu niezbędnego dla modeli ORM. Nie mamy też czasu (ani ochoty) aby siedzieć i stworzyć definicje do wszystkich tabel wraz z wyposażeniem ich w nasze własne, dodatkowe metody uwzględniające każdą, możliwą potrzebę w przyszłości. Zamiast tego, wolimy tworzyć i rozbudowywać obiektowy opis naszej bazy dla wszystkich aplikacji w miarę ich rozwoju i wzrostu złożoności. Chcemy oby nasz model biznesowy, opisywany przez ActiveRecord, rósł stopniowo wraz ze wzrostem naszych aplikacji RoR.

Do takiego zadania, najlepiej aby wszystkie aplikacje RoR korzystały ze wspólnego repozytorium modeli. W wypadku systemów POSIX (Linux, czy MacOS-X) najprościej to rozwiązać za pomocą linków symbolicznych. Jednakże, jeśli chcemy aby nasz kod był bardziej przenośny i działał także pod Windowsami musimy inaczej podejść do tego problemu: wyniesiemy definicje naszych modeli do zewnętrznych modułów Rubiego aby domieszkowały one klasy poszczególnych modeli Rails.

Wpierw musimy dla każdej aplikacji RoR wskazać gdzie leży repozytorium z wpołdzielonymi modułami. Najlepiej wstawić do pliku conf/environment.rb zmienną globalną Rubiego o nazwie, np. $SHARED.

$SHARED = File.dirname(__FILE__)+'/../../shared/'

Konstrukcja File.dirname… jest zalecana, gdyż daje pewny i jednoznaczny dostęp do pliku bez względy na to gdzie przekopiujemy cały nasz projekt. (Identycznie należy robić pod PHP aby uniknąć problemów z ustawieniami zmiennej include_dirs. Większość pehapowego lamerstwa używa zapisu require(“plik.php”) i potem się dziwi że coś im nie działa)

Załóżmy że wcześniej mieliśmy model zdefiniowany następująco:

class Book
  set_table_name 'ksiazki'
  belongs_to :author
  def self.commented(user_id)
    self.find(:all, :conditions=>['user_id=?',user_id])
  end
end

Mamy tu więc nie tylko nazwę tabeli niezgodną z konwencją Railsów, ale także dodatkową metodę klasową. Wpierw zróbmy z tego moduł:

module BookModule
  def self.extended(c)
    c.set_table_name 'ksiazki'
    c.belongs_to :author
  end
  def commented(user_id)
    self.find(:all, :conditions=>['user_id=?',user_id])
  end
end

Kod korzystający z tego modułu przyjmie postać:

if RAILS_ENV == "development"
  load $SHARED + 'models/book.rb'
else
  require $SHARED + 'models/book.rb'
end

class Book< ActiveRecord::Base
  include BookModule
  extend BookModule
end

Górny fragment jest potrzebny jeśli chcemy aby Webrick/Mongrel w trybie development się przeładowywał podczas zmiany kodu w Ruby. “include” włącza metody instancji. Zaś “extend” włącza wszystkie emetody modułu _BookModule _do klasy jako jej metody klasowe. Zwróć uwagę, że w module nie definiowaliśmy ich jako z prefiksem self. Co prawda, efektem ubocznym tego przykładu jest to, że metoda commented() będzie możliwa do uruchomienia jako metoda zarówno instancji jak i klasy, ale to raczej nie ma żadnego znaczenia.

Posted in  | Tagi , ,  | 11 comments