#201 Bundler
201: Bundler (view original Railscast)
In dieser Episode führen wir unsere Vorschau auf die neuen Features von Rails 3 fort. Dieses Mal werfen wir einen Blick auf Bundler, die neue Art, Gem-Abhängigkeiten von Rails-Applikationen zu verwalten.
Bundler wird momentan stetig weiterentwickelt, also geht man am Besten sicher, die aktuellste Version installiert zu haben, indem man
gem install bundler
ausführt. Hierbei bitte beachten, dass nicht sudo
eingesetzt wird, da hier eine mit rvm
installierte Version von Ruby verwendet wird.
Wie man Bundler benutzt, um Gems zu installieren
In der letzten Episode hatten wir das Problem, dass uns der sqlite3-ruby
Gem gefehlt hatte. Wir haben dieses Problem von Hand gelöst, indem wir den Gem per gem install
nachinstalliert haben.
gem install sqlite3-ruby
Wir hätten Dies alternativ auch mit Bundler machen können, da in den Abhängigkeiten unserer Applikation sqlite3-ruby
aufgeführt ist, also im Gemfile
unserer Applikation aufgelistet ist. Um die Abhängigkeiten aufzulösen, führen wir bundle install
aus, was alle Einträge durchgeht und sie bei Bedarf nachinstalliert.
$ bundle install Fetching source index from http://gemcutter.org Resolving dependencies Installing abstract (1.0.0) from system gems Installing actionmailer (3.0.0.beta) from system gems Installing actionpack (3.0.0.beta) from system gems Installing activemodel (3.0.0.beta) from system gems Installing activerecord (3.0.0.beta) from system gems Installing activeresource (3.0.0.beta) from system gems Installing activesupport (3.0.0.beta) from system gems Installing arel (0.2.1) from rubygems repository at http://gemcutter.org Installing builder (2.1.2) from system gems Installing bundler (0.9.5) from system gems Installing erubis (2.6.5) from system gems Installing i18n (0.3.3) from system gems Installing mail (2.1.2) from system gems Installing memcache-client (1.7.8) from system gems Installing mime-types (1.16) from system gems Installing rack (1.1.0) from system gems Installing rack-mount (0.4.7) from rubygems repository at http://gemcutter.org Installing rack-test (0.5.3) from system gems Installing rails (3.0.0.beta) from system gems Installing railties (3.0.0.beta) from system gems Installing rake (0.8.7) from system gems Installing sqlite3-ruby (1.2.5) from system gems Installing text-format (1.0.0) from system gems Installing text-hyphen (1.0.0) from system gems Installing thor (0.13.1) from rubygems repository at http://gemcutter.org Installing tzinfo (0.3.16) from system gems Your bundle is complete!
Anhand der Ausgabe kann man erkennen, dass Bundler alle Gems, die von der Applikation benötigt werden, einschließlich sqlite3-ruby
installiert hat. Wäre ein Gem noch nicht installiert gewesen, hätte Bundler ihn von Gemcutter heruntergeladen und nachinstalliert.
Im Zweifelsfall kann man also einfach immer bundle install
ausführen, um alle Abhängigkeiten auflösen zu lassen. Immer, wenn man eine neue Applikation erzeugt oder wenn man auf fremden Code zurückgreift, sollte man dieses Kommando laufen lassen, um sicherzugehen, dass man die richtigen Gems installiert hat. Auch beim Ausliefern einer Applikation sollte diese Überprüfung auf dem Produktivsystem stattfinden. Man kann das Kommando auch einfach zu seinen deployment recipes
hinzufügen, damit es immer beim Ausliefern automatisch ausgeführt wird.
Es ist jedoch wichtig, zu beachten, dass man niemals sudo
verwenden sollte, wenn man bundle install
ausführt, auch wenn es sonst man beim Installieren von Gems normalerweise tut.
Gem-Abhängigkeiten in einer Applikation registrieren
Wie fügen wir also solche Abhängigkeiten zu unserer Applikation hinzu? In früheren Rails-Versionen wurden diese in der /config/environment.rb
-Datei vermerkt, was sich mit Rails 3 jedoch geändert hat. Die benötigten Gems werden jetzt in einer Gemfile
genannten Datei im Rootverzeichnis der Applikation notiert. Das Gemfile
einer neuen Rails-Applikation sieht so aus:
# Edit this Gemfile to bundle your application's dependencies. source 'http://gemcutter.org' gem "rails", "3.0.0.beta" ## Bundle edge rails: # gem "rails", :git => "git://github.com/rails/rails.git" # ActiveRecord requires a database adapter. By default, # Rails has selected sqlite3. gem "sqlite3-ruby", :require => "sqlite3" ## Bundle the gems you use: # gem "bj" # gem "hpricot", "0.6" # gem "sqlite3-ruby", :require => "sqlite3" # gem "aws-s3", :require => "aws/s3" ## Bundle gems used only in certain environments: # gem "rspec", :group => :test # group :test do # gem "webrat" # end
Einige Gems sind in dieser Datei schon vermerkt, einschließlich rails
und sqlite3-ruby
. Besonders beachten sollte man die Versionsnummer in der Zeile, die auf den rails
Gem verweist. Zu jeder Referenz in dieser Datei kann man eine bestimmte Version spezifizieren, um eine ganz bestimmte Version eines Gems verwenden zu lassen. Um zu einem bestimmten Zeitpunkt auf eine neue Rails-Version umzusteigen, muss man die Version einfach in dieser Datei vermerken, anstatt wie früher in der environment.rb
.
Um zusätzliche Gems in unserer Applikation zu verwenden, muss man sie einfach nur in dieser Datei vermerken. Beispielsweise kann man will_paginate
so einbinden:
gem "will_paginate", ">=2.3.12"
Der zweite Parameter gibt an, dass die Version 2.3.12 oder neuer des Gems verwendet werden soll. Sobald dieser Verweis in dem Gemfile
steht, kann man den Gem per bundle install
automatisch installieren lassen, doch vorher kann man mithilfe von bundle check
die Abhängigkeiten prüfen lassen:
$ bundle check The following dependencies are missing * will_paginate (>= 2.3.12, runtime)We can install the missing gems by running bundle install again.
Um eine Auflistung aller verfügbaren Bundle Kommandos zu sehen, gibt man bundle help
ein:
$ bundle help Tasks: bundle check # Checks if the dependencies listed in Gemfile are satisfied by currently installed gems bundle exec # Run the command in context of the bundle bundle help [TASK] # Describe available tasks or one specific task bundle init # Generates a Gemfile into the current working directory bundle install # Install the current environment to the system bundle lock # Locks the bundle to the current set of dependencies, including all child dependencies. bundle pack # Packs all the gems to vendor/cache bundle show # Shows all gems that are part of the bundle. bundle unlock # Unlock the bundle. This allows gem versions to be changed
Andere Möglichkeiten des Gemfiles
Betrachten wir weiterhin das Gemfile
und was wir noch damit machen können. Ein sehr nützliches neues Feature ist die Möglichkeit, Gems direkt aus einem git
repository zu bekommen. Um beispielsweise immer auf dem aktuellsten Stand der Entwicklung zu sein, kann man den rails
Gem auf das zentrale Entwicklungs-repository verweisen lassen:
# Bundle edge rails: gem "rails", :git => "git://github.com/rails/rails.git"
Dieses Feature eröffnet mächtige neue Möglichkeiten! Wenn ein Gem nicht ganz so funktioniert, wie wir uns vorstellen, können wir das Projekt auf github forken, den Code nach eigenem Ermessen verändern und die Gem-Abhängigkeit auf unser github repository verweisen lassen.
Man kann Gems allerdings auch auf eine bestimmte Umgebung beschränken. Um RSpec
für Testzwecke zu laden, kann man Folgendes notieren:
gem "rspec", :group => :test
Wenn man gleich mehrere Gems in einer bestimmten Umgebung laden möchte, kann man group
auch einen Block übergeben:
group :test do gem "webrat" get "rspec" end
Lässt man bundle install
jetzt laufen, werden alle Gems für alle Umgebungen installiert:
$ bundle install Fetching source index from http://gemcutter.org Resolving dependencies ... Installing rspec (1.3.0) from rubygems repository at http://gemcutter.org ... Installing webrat (0.7.0) from rubygems repository at http://gemcutter.org Installing will_paginate (2.3.12) from system gems Your bundle is complete!
Wie man der (verkürzten) Ausgabe entnehmen kann, wurden die Gems aus unserem Gemfile
installiert.
Wenn man Gems aus einer bestimmten Umgebung nicht installieren will, verwendet man die Option--without
. Um also alle Gems ohne die aus der test
-Umgebung zu installieren, führt man Folgendes aus:
bundle install --without=test
Dies ist besonders hilfreich, wenn man seine Applikation auf dem Produktivsystem installieren will, ohne die ganzen Gems, die fürs Testen benötigt werden, mitzuinstallieren.
Gems sperren
Ein weiteres sehr nützliches Kommando ist bundle lock
. Es sperrt die exakten Versionen der Gems, die unsere Applikation nutzt. Nachdem dieses Kommando ausgeführt wurde, existiert eine neue Datei mit dem Namen Gemfile.lock
. Diese Datei listet alle Gems zusammen mit ihrer jeweiligen Version auf, die für unsere Applikation installiert wurden. Nach der Ausführung von bundle lock
werden durch bundle install
nur noch genau die Gems in den Versionen installiert, die im Gemfile.lock
vermerkt sind, selbst wenn neuere Versionen verfügbar sein sollten.
Wenn man mit anderen Rails-Entwicklern zusammen an einem Projekt arbeitet, kann man bundle lock
verwenden, um sicherzugehen, dass Jeder die gleichen Versionen aller benötigten Gems verwendet. Das Gleiche gilt beim Deployment einer Applikation auf das Produktivsystem. Falls eine Applikation auf einen anderen Server umziehen muss, will man sichergehen, dass exakt die gleichen Voraussetzungen vorherrschen wie auf unserem Entwicklungssystem.
Muss man zu einem späteren Zeitpunkt Änderungen an den Abhängigkeiten vornehmen, sollte man allerdings nicht einfach das Gemfile.lock
verändern. Stattdessen bringt man das Gemfile
auf den gewünschten Stand und führt das bundle install
-Kommando mit der zusätzlichen Option --relock
aus:
bundle install --relock
Dadurch werden die Gems entsperrt, auf die gewünschte Version gebracht und wieder gesperrt.
Gems in der Applikation installieren
Das letzte zu betrachtende Feature ist bundle pack
. Normalerweise installiert Bundler alle Gems im .bundle
-Verzeichnis im Hauptverzeichnis des aktuellen Benutzers:
$ ls ~/.bundle cache doc gems ruby specifications
Daraus folgt natürlich, dass die Gems nicht im Verzeichnis der jeweiligen Applikation liegen und damit auch nicht im verwendeten Versionskontrollsystem landen. Möchten wir allerdings die Gems mit unserer Anwendung ausliefern, können wir bundle pack
verwenden:
bundle pack Copying .gem files into vendor/cache * memcache-client-1.7.8.gem * rspec-1.3.0.gem * thor-0.13.3.gem * tzinfo-0.3.16.gem * builder-2.1.2.gem * nokogiri-1.4.1.gem * mime-types-1.16.gem * sqlite3-ruby-1.2.5.gem * i18n-0.3.3.gem * abstract-1.0.0.gem * erubis-2.6.5.gem * text-hyphen-1.0.0.gem * bundler-0.9.6.gem * rake-0.8.7.gem * will_paginate-2.3.12.gem * text-format-1.0.0.gem * rack-1.1.0.gem * rack-test-0.5.3.gem * webrat-0.7.0.gem * rack-mount-0.4.7.gem * activesupport-3.0.0.beta.gem * mail-2.1.2.gem * arel-0.2.1.gem * activemodel-3.0.0.beta.gem * actionpack-3.0.0.beta.gem * actionmailer-3.0.0.beta.gem * activerecord-3.0.0.beta.gem * activeresource-3.0.0.beta.gem * railties-3.0.0.beta.gem * rails-3.0.0.beta.gem
Damit werden die .gem
-Dateien, die unsere Applikation verwendet, ins Verzeichnis /vendor/cache
der Applikation kopiert (wobei das Verzeichnis bei Bedarf erzeugt wird, wenn es noch nicht existiert). Alle so gespeicherten Gems werden danach aus diesen .gem
-Dateien installiert, anstatt sie beispielsweise von Gemcutter zu laden. Normalerweise sollte man dieses Feature nicht all zu oft benötigen, doch wenn man in die Situation kommt, dass das Produktivsystem keine Möglichkeit hat, Gems von Gemcuttoer oder anderen Quellen herunterzuladen, leistet einem bundle pack
gute Dienste.
Damit beenden wir die aktuelle Episode. Wir hoffen, sie hat Ihnen einen guten Überblick vermittelt, wie man Bundler einsetzen kann, um Gems und Abhängigkeiten zu verwalten. Nach einer kurzen Einarbeitungszeit kann Bundler die Probleme, die oft mit diesen Abhängigkeiten bestanden haben, endgültig zur Vergangenheit gehören lassen.
Zu guter letzt möchten wir Sie noch auf railsplugins.org hinweisen, falls Sie sich gefragt haben, welche Gems und Plugins mit Rails 3 funktionieren. Auf dieser Seite können Sie Plugins und Gems durchsuchen, ob sie mit Rails 3 und Ruby 1.9 funktionieren.
Falls ein Gem als "not working" aufgelistet ist, ist dies eine grossartige Möglichkeit, einfach mitzuarbeiten! Auf diese Weise können Sie mithelfen, so viele Gems und Plugins wie möglich für Rails 3 zu portieren.