Migracje w Ruby on Rails

Posted by wiktor on May 31, 2007 in Ruby on Rails

Widzę, że jesteś pierwszy raz na moim blogu. Witaj :). Może nawet będziesz miał ochotę subskrybować blog poprzez RSS. Trzymaj się ciepło!

Ostatnio część czasu w pracy poświęcam na rozwijaniu projektu RubyTime. Jest to open-source’owa aplikacja napisana w Ruby on Rails do zliczania czasu pracy w małych firmach (ang. time tracker albo time-sheets) i następnego rozliczania pracowników i wystawiania faktur na tej podstawie klientom. Przy dodawaniu nowej funkcjonalności pierwszy raz skorzystałem z mechanizmu migracji, które oferuje Ruby on Rails. Muszę przyznać, że jestem pod wrażeniem prostoty tego rozwiązania.

Przede wszystkim zaskoczyło mnie inne podejście do projektowania baz danych. Oczywiście zastosowane podejście jest pochodną częstego stosowania w rozwijaniu aplikacji RoR metodyk lekkich/zwinnych (XP, Scrum). W nich z założenia przyjmuje się omylność przy projektowaniu, a krótkie iteracje służą do poprawiania/refaktoryzacji aplikacji. Dobre projektowanie baz danych nigdy nie było łatwym zajęciem, a pomyłki były częste. Nie raz zdarzało mi się, że zaprojektowana BD musiała zostać trochę zmieniona ze względu na zbędą redundancję albo efektywność albo czegoś zabrakło.

Ruby on Rails poprzez dostarczenie mechanizmu migracji pozwala na szybkie rozwijanie aplikacji i następnie poprawianie usterek. Trzeba podkreślić, że dodawanie nowej funkcjonalności staje się równie miłe i przyjemne.

Zobaczmy to na przykładzie :) .

Powiedzmy, że mamy już istniejącą aplikację. Naglę się zorientowaliśmy, że zapomnieliśmy wprowadzić systemu logowania dla użytkowników :) . Czyli mamy model User, a w bazie danych ponad 1000 rekordów. Coś trzeba zrobić. Zacznijmy od wygenerowania nowej migracji:

$ ruby script/generate migration AddLoginAndPassword
exists db/migrate
create db/migrate/002_add_login_and_password.rb

Teraz zabierzmy sie do edytowania pliku 002_add_login_and_password.rb.

#
# Migracja zmienia model użytkownika i dodaje do niego 2 kolumny:
#   - login (domyślna wartość to pierwsze słowo nazwy użytkownika)
#   - password (domyślna wartość to login użytkownika)
#
class AddLoginAndPassword < ActiveRecord::Migration
    def self.up
        add_column :users, :login, :string, :null => false
        add_column :users, :password, :string, :null => false
        User.find(:all).each { |user|
            user.login = user.name.scan(/\w+/)[0].strip.downcase
            user.password = Digest::SHA1.hexdigest(user.user)
            user.save
        }
    end
 
    def self.down
        remove_column :users, :login
        remove_column :users, :password
    end
end

Powyższy kod jest bardzo czytelny i widać od razu, co on robi. Wartym podkreślenia jest fakt, że migracje pozwalają nie tylko zmieniać strukturę bazy danych, ale także wypełniać ją jakimiś danymi. Jest to bardzo przydatne, gdy wprowadzamy nową funkcjonalność. Teraz zostaje nam tylko dodać do modelu więzy spójności i odpalić:

rake db:migrate VERSION=2

Voilà! :)

3 Comments

Radarek
Jun 1, 2007 at 11:02 am

Migracje są świetne, ale dlatego, że praktycznie wszystko w Railsach jest przemyślane. Sam w jednym z projektów w php przeportowałem ten mechanizm i zmiany w bazie były wykonywane za pomocą migracji :) .


 
rowery
Aug 7, 2007 at 12:06 pm

Migracje są OK.Polecam wszystkim.
Pozdrawiam autora.


 
Marek Kirejczyk
Oct 11, 2007 at 7:26 pm

Istnieje przy takim migrownaniu pewne niebezpieczeństwo. Zauważmy, że używasz tu modelu User i jego metody find. W niektórych przypadkach może zaistnieć pokusa by użyć innych metod modelu, ale w zdefinowanych przez programistę. Wyobraźmy sobie co się stanie z taką migracją po zmianie nazwy takiej metody…
Migracje przestaną działać, ponieważ model na którym była oparta stara migracja już się zmienił.
Dlatego stosuje się takie rozwiązanie:
[ruby]
class AddLoginAndPassword < ActiveRecord::Migration
class User < ActiveRecord::Base

end

….
end
[/ruby]
Pozwala to na używanie w migracji tylko metod zdefiniowanych przez ActiveRecord i zabezpiecza przed przyszłymi błędami.


 

Reply

Copyright © 2010 Mocna Kawa All rights reserved. Theme by Laptop Geek.