Więcej na rubyonrails.pl: Start | Pobierz | Wdrożenie | Kod (en) | Screencasty | Dokumentacja | Ekosystem | Forum | IRC

Rails on Rack

Ten przewodnik opisuje integrację Railsów z interfejsem serwera webowego Rack oraz komunikację z wykorzystaniem innych komponentów frameworka Rack. Zapoznanie się z tym przewodnikiem pozwoli ci na:

Ten przewodnik zakłada praktyczną znajomość założeń frameworka Rack i związanych z nim pojęć takich jak obiekty middleware, mapowanie url (url maps), czy obiekt Rack::Builder.

1 Wprowadzenie do Rack

Rack dostarcza minimalnego, modułowego i adaptowalnego interfejsu do rozwijania aplikacji webowych w Rubym. Poprzez żądania i odpowiedzi HTTP w najprostszej możliwej postaci unifikuje i łączy w sobie API dla serwerów WWW, frameworków webowych i oprogramowania pośredniczącego (tzw. middleware software) w jedną metodę zapytania.

- Dokumentacja Rack API

Note: Interfejs serwera webowego umożliwia komunikację (ang. interfacing) aplikacji webowej z serwerem WWW, inną aplikacją lub frameworkiem webowym. Przyjęło się mylne utożsamianie interfejsu z węższym pojęciem interfejsu użytkownika (komunikacja aplikacja-użytkownik). -przypis tłumacza

Wyjaśnienie czym dokładnie jest Rack nie jest zadaniem tego przewodnika. Jeśli nie jest ci on jeszcze znany, sięgnij po któreś z tych źródeł :

2 Rails on Rack

2.1 Obiekty Rack w Aplikacjach Railsowych

ActionController::Dispatcher.new to podstawowy obiekt aplikacji Rack występujący w aplikacjach Railsowych. Każdy z serwerów WWW zgodnych z Rack powinien posłużyć się tym obiektem, aby obsłużyć aplikację Railsową.

2.2 script/server

script/server stanowi Railsowy odpowiednik skryptu Rack rackup. Jego zadaniem jest stworzenie obiektu Rack::Builder i uruchomienie serwer WWW.

Oto jak script/server tworzy instancję Rack::Builder:

app = Rack::Builder.new { use Rails::Rack::LogTailer unless options[:detach] use Rails::Rack::Debugger if options[:debugger] use ActionDispatch::Static run ActionController::Dispatcher.new }.to_app

Obiekty middleware zastosowane w powyższym kodzie przydają się praktycznie tylko w środowisku rozwojowym. Poniższa tabela opisuje ich użycie:

Middleware Zastosowanie
Rails::Rack::LogTailer Dołącza zawartość logu do konsoli
ActionDispatch::Static Zapisuje statystyki serwera w katalogu RAILS_ROOT/public
Rails::Rack::Debugger Uruchamia Debuggera

2.3 rackup

Aby stosować skrypt rackup zamiast Railsowego script/server, możesz umieścić następujący kod w pliku config.ru w katalogu głównym aplikacji:

# RAILS_ROOT/config.ru require "config/environment" use Rails::Rack::LogTailer use ActionDispatch::Static run ActionController::Dispatcher.new

Następnie uruchomić serwer:

[lifo@null application]$ rackup config.ru

Aby sprawdzić dostępne opcje rackup wywołaj:

[lifo@null application]$ rackup --help

3 Stos middleware modułu Action Controller

Wiele komponentów modułu Action Controller jest zaimplementowanych jako obiekty middleware Rack. ActionController::Dispatcher używa ActionController::MiddlewareStack, aby łącząc różne wewnętrzne i zewnętrzne obiekty middleware stworzyć kompletną Railsową aplikację Rack.

ActionController::MiddlewareStack stanowi Railsowy odpowiednik obiektu Rack::Builder, ale nieco bardziej elastyczniejszy i dostosowany do wymagań Railsów.

3.1 Podgląd stosu middleware

Aby wyświetlić zawartość stosu middleware, który jest aktualnie w użyciu posłużymy się zadaniem rake:

$ rake middleware

Oto jak mógłby wyglądać rezultat tego zapytania dla świeżo wygenerowanej aplikacji:

use Rack::Lock use ActionController::Failsafe use ActionController::Session::CookieStore, , {:secret=>"<secret>", :session_key=>"_<app>_session"} use Rails::Rack::Metal use ActionDispatch::RewindableInput use ActionController::ParamsParser use Rack::MethodOverride use Rack::Head use ActiveRecord::QueryCache run ActionController::Dispatcher.new

Zadania poszczególnych obiektów middleware objaśnione zostały w sekcji Stos wewnętrznych obiektów Middleware.

3.2 Konfiguracja stosu middleware

Railsy dostarczają nam prostego interfejsu konfiguracyjnego config.middleware dzięki któremu dodamy, usuniemy i zmodyfikujemy obiekty ze stosu poprzez environment.rb lub plik konfiguracji określonego środowiska environments/<environment>.rb.

3.2.1 Dodanie obiektu middleware

Aby dodać obiekt middleware do stosu możesz posłużyć się dowolną z poniższych metod:

  • config.middleware.use(new_middleware, args) – Dodaje nowy obiekt middleware na dnie stosu.
  • config.middleware.insert_before(existing_middleware, new_middleware, args) – Dodaje nowy obiekt middleware przed wskazanym, istniejącym obiektem middleware.
  • config.middleware.insert_after(existing_middleware, new_middleware, args) – Dodaje nowy obiekt middleware za wskazanym, istniejącym obiektem middleware.

Przykład:

# config/environment.rb # Odłóż Rack::BounceFavicon na dno stosu config.middleware.use Rack::BounceFavicon # Dodaj Lifo::Cache za ActiveRecord::QueryCache. # Przekaż argument { :page_cache => false } do Lifo::Cache. config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, :page_cache => false
3.2.2 Zamiana obiektów middleware

Możesz podmienić istniejący obiekt ze stosu middleware za pomocą config.middleware.swap.

Przykład:

# config/environment.rb # Zamień ActionController::Failsafe na Lifo::Failsafe config.middleware.swap ActionController::Failsafe, Lifo::Failsafe
3.2.3 Stos middleware jest tablicą

Stos middleware zachowuje się jak zwykła tablica. Możesz posłużyć się metodami odpowiednimi dla tablic, aby dodać, zmienić kolejność lub usunąć elementy stosu. Metody przestawione powyżej są po prostu wygodniejsze.

Przykładowo, poniższe polecenie usunie obiekty middleware odpowiadające podanej nazwie klasy:

config.middleware.delete(middleware)

3.3 Stos wewnętrznych obiektów Middleware

Znaczna część funkcjonalności modułu Action Controller opiera sie na stosowaniu obiektów middleware. Poniższa tabela przedstawia ich użycie:

Middleware Zastosowanie
Rack::Lock Podnosi flagę env["rack.multithread"] i przełącza aplikację w tryb Mutex.
ActionController::Failsafe Zwraca klientowi status HTTP 500 jeśli podczas wysyłania wystąpiły jakieś wyjątki.
ActiveRecord::QueryCache Aktywuje cache dla zapytań w module Active Record.
ActionController::Session::CookieStore Przełącza na użycie cookie do przechowywania sesji.
ActionController::Session::MemCacheStore Przełącza na użycie pamięci memcached do przechowywania sesji.
ActiveRecord::SessionStore Użycie bazy danych do przechowywania sesji.
Rack::MethodOverride Ustanawia metodę HTTP na podstawie parametru _method lub env["HTTP_X_HTTP_METHOD_OVERRIDE"].
Rack::Head Odrzuca wartość body odpowiedzi, jeśli klient przesłał żądanie HEAD.

Możesz użyć powyższych obiektów middleware w stworzonym przez siebie stosie Rack.

3.4 Dostosowanie wewnętrznego stosu middleware

Możesz zamienić cały stos middleware przy pomocy ActionController::Dispatcher.middleware=.

Przykład:

Umieść następujący kod w initializers:

# config/initializers/stack.rb ActionController::Dispatcher.middleware = ActionController::MiddlewareStack.new do |m| m.use ActionController::Failsafe m.use ActiveRecord::QueryCache m.use Rack::Head end

Podgląd stosu middleware:

$ rake middleware (in /Users/lifo/Rails/blog) use ActionController::Failsafe use ActiveRecord::QueryCache use Rack::Head run ActionController::Dispatcher.new

3.5 Stosowanie obiektu Rack Builder

Oto sposób, na to by zamiast Railsowego MiddlewareStack stosować Rack::Builder

Wyczyść istniejący stos middleware

# environment.rb config.middleware.clear


Umieść plik config.ru w katalogu RAILS_ROOT

# config.ru use MyOwnStackFromStratch run ActionController::Dispatcher.new

4 Metalowe aplikacje Railsowe

Metalowe aplikacje Railsowe to minimalne aplikacje Rack, zaprojektowane tak, aby ściśle łączyły się z typowymi aplikacjami Railsowymi. Jako że Metalowe aplikacje Railsowe pomijają cały stos modułu Action Controller, obsługa żądania nie obciąża w ogóle samych Railsów. Może to być istotne w szczególnych przypadkach, kiedy wydajność stosu frameworka Rails sprawia problemy.

Ryan Bates stworzył interesujący screencast, w którym omawia generowanie i stosowanie Metalowych aplikacji Railsowych.

4.1 Generowanie Metalowej aplikacji Railsowej

Railsy dostarczają generatora metal, który umożliwia tworzenie tego typu aplikacji:

$ script/generate metal poller

Zawartość pliku poller.rb wygenerowanego w katalogu app/metal:

# Allow the metal piece to run in isolation require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails) class Poller def self.call(env) if env["PATH_INFO"] =~ /^\/poller/ [200, {"Content-Type" => "text/html"}, ["Hello, World!"]] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end end end

Aplikacje znajdujące się w app/metal w katalogu wtyczek również zostaną odnalezione i dodane do listy.

Celem aplikacji Metalowych jest optymalizacja. Zanim zdecydujesz się na ich stosowanie upewnij się, że pojąłeś konsekwencje stosowania powiązanego działania. Zacznij od przeczytania postu Performance of Rails Metal na weblogu projektu.

4.2 Kolejność wykonania

Wszystkie aplikacje Metalowe uruchamiane są przez obiekt middleware Rails::Rack::Metal, który jest częścią łańcucha ActionController::MiddlewareStack.

Oto podstawowa metoda odpowiedzialna za działanie aplikacji Metalowej:

def call(env) @metals.keys.each do |app| result = app.call(env) return result unless result[0].to_i == 404 end @app.call(env) end

Zmienna @metals w powyższym kodzie to posortowana tablica asocjacyjna. Ze względu na domyślne sortowanie alfabetyczne plik aaa.rb znajdzie się przed bbb.rb w łańcuchu.

Można zastąpić domyślne sortowanie w twoim środowisku. Wystarczy dodać następującą linijkę do pliku config/environment.rb

config.metals = ["Bbb", "Aaa"]

Każdy łańcuch w tej tablicy powinien odpowiadać nazwie twojej metalowej klasy. Pamiętaj, że aplikacje Metalowe, które nie znajdą się na tej liście nie zostaną wczytane.

Aplikacje metalowe nie mogą zwracać statusu HTTP 404, ponieważ jest on używany przy wywoływaniu łańcucha Metalowego. Jeśli zajdzie taka konieczność posłuż się standardowym kontrolerem, lub odpowiednio zaadaptowanym obiektem middleware.

5 Resources

5.1 Nauka Rack

5.2 Objaśnienie zasad działnia obiektów Midlleware

6 Changelog

Lighthouse ticket

  • February 7, 2009: Second version by Pratik
  • January 11, 2009: First version by Pratik