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.

Zakładam, że na początek może byśmy chcieli popróbować Sequela tak, aby można było szybko przełączyć się z powrotem na Active Record. Po doinstalowaniu gema sequel , należy przejść do pliku config/environment.rb i dodać gdzieś następujący kod:

require 'sequel'
DB = Sequel 'mysql://login:[email protected]/nazwa_bazy'

Obiekt DB jest wielowątkowym połaczeniem z bazą definiowaną za pomocą URI. Jak ktoś, chce to można automatycznie zassać dane o bazie z pliku config/database.sql

require 'sequel'
conf = YAML.load_file(config.database_configuration_file)[ENV['RAILS_ENV']]
DB = Sequel "#{conf['adapter']}://#{conf['username']}:#{conf['password]}@#{conf['host']}/#{conf['database']}"  

Następnie w modelu można dodać sobie warunek tak, aby trzymać obie wersje kodu, dla AR i dla Sequela (potem można wywalić to, co nie jest potrzebne).

if DB
  # Wersja dla Sequel
  class Preference < Sequel::Model(:preferences)
    def user
      User.filter(:id => user_id)
    end
  end
else 
  # Wersja dla Active Record
  class Preference < ActiveRecord::Base
    belongs_to :user
  end
end

Zamiast metody user można użyć makra one_to_one :user, :from => :User ale ja wolę stworzyć własną metodę. Robi nie tylko to samo, ale także nie trzeba pamiętać dodatkowych opcji w razie nietypowej struktury. Poza tym w podanym przykładzie zwracany jest obiekt proxy, a nie lista obiektów. Daje to możliwości poza zasięgiem Active Record. Mogę rozbudowywać zwracany obiekt o kolejne metody. Na każdym etapie mam podgląd do wygenerowanego SQL’a.

Preference.first.user.sql
=> "SELECT * FROM users WHERE (`id` = 1)"

Preference.first.user.order(:name).sql
=>  "SELECT * FROM users WHERE (`id` = 1) ORDER BY `name`"

Preference.first.user.order(:name).select(:users.all).sql
=> "SELECT users.* FROM users WHERE (`id` = 1) ORDER BY `name`"

Albo inny przykład

class Post < Sequel::Model(:posts)
  def dataset.old_posts
    filter {:stamp < 30.days.ago}
  end    
  def dataset.clean_old_posts
    old_posts.delete
  end
end

I można teraz napisać tak:

Post.filter(:category => 'ruby').clean_old_posts

Tagi , ,  | 6 comments

Comments

  1. Avatar pnowak powiedział 2 days later:

    czyli jak rozumiem bez problemu mozna integrowac sequel z RoR ?

  2. Avatar Jarosław Zabiełło powiedział 2 days later:

    @pnowak: toż to cały tekst jest temu poświęcony. :)

  3. Avatar pnowak powiedział 4 days later:

    tak, wiem ale nie poruszono tutaj chocby tematow testowania, walidatorow itd. czy w rails sa zaszyste jakies zaleznosci z ar na stale ktore nie pozwola na korzystanie z sequel w pelnym zakresie ?

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

    Generalnie Sequel preferuje podejście minimalistyczne – czysty Ruby i mniej magii. Np. zaleca pisanie metod klasowych rozszerzających podstawowy model ORM zamiast polegania na makrach/helperach do tworzenia powiązań relacyjnych. Co do walidatorów to jest validatable którego metody powinny dać się wstrzyknąć do Sequela, ale się tym nie bawiłem.

  5. Avatar Uzytkownik powiedział 15 days later:
    Kod tworzący DB jest chyba znacznie prostszy:
    
    DB = Sequel(YAML.load_file(config.database_configuration_file)[ENV['RAILS_ENV']])
    
    

    Nie jest to 100% kompatybilne (ale i podana metoda nie jest).

  6. Avatar pg powiedział 23 days later:

    Uzytkownik: niestety adapter MySQL w Sequelu wymaga :user zamiast :username, a poza tym wczytanie database.yml zwróci klucze w postaci String a nie Symbol, czego już Sequel nie przetrawi. Ja wykombinowalem coś takiego:

    arc = ActiveRecord::Base.configurations[ENV['RAILS_ENV']].symbolize_keys DB = Sequel(arc,:user=>arc[:username])

    Przetestowane na Sequel 1.0.

(leave url/email »)

   Pomoc języka formatowania Obejrzyj komentarz