Co to jest Rack middleware?

Czym jest Rack middleware w Ruby? Nie mogłem znaleźć dobrego wytłumaczenia, co mają na myśli przez "middleware".

Author: chrisgoyal, 2010-02-13

9 answers

Regał jako konstrukcja

Rack middleware jest czymś więcej niż "sposobem filtrowania żądania i odpowiedzi" - jest to implementacja pipeline design pattern dla serwerów WWW korzystających z Rack.

Bardzo czysto oddziela poszczególne etapy przetwarzania wniosku - rozdzielenie problemów jest kluczowym celem wszystkich dobrze zaprojektowanych produktów.

Na przykład z Rackiem mogę mieć oddzielne etapy rurociągu robi:

  • Uwierzytelnianie: czy po otrzymaniu żądania dane logowania użytkowników są poprawne? Jak zweryfikować OAuth, podstawowe uwierzytelnianie HTTP, nazwę / hasło?

  • Autoryzacja : "czy użytkownik jest upoważniony do wykonywania tego konkretnego zadania?", czyli bezpieczeństwo oparte na rolach.

  • Buforowanie: czy przetworzyłem już to żądanie, Czy Mogę zwrócić wynik buforowany?

  • Dekoracja : Jak mogę ulepszyć żądanie, aby usprawnić przetwarzanie na późniejszym etapie?

  • Monitorowanie wydajności i użycia: jakie statystyki mogę uzyskać z żądania i odpowiedzi?

  • Wykonanie: faktycznie obsłużyć żądanie i dostarczyć odpowiedź.

Możliwość oddzielenia poszczególnych etapów (i opcjonalnie ich włączenia) jest bardzo pomocna w tworzeniu dobrze ustrukturyzowanych aplikacji.

Społeczność

Jest też świetny eko-system rozwój wokół oprogramowania pośredniego Rack - powinieneś być w stanie znaleźć wstępnie zbudowane komponenty rack, aby wykonać wszystkie powyższe kroki i więcej. Zobacz Rack GitHub wiki, aby uzyskać listę middleware .

Co To jest Middleware?

[2]}Middleware jest strasznym terminem, który odnosi się do każdego komponentu oprogramowania/biblioteki, która pomaga, ale nie jest bezpośrednio zaangażowana w wykonanie jakiegoś zadania. Bardzo powszechnymi przykładami są rejestrowanie, uwierzytelnianie i inne wspólne, poziome przetwarzanie komponenty . Są to zazwyczaj rzeczy, których każdy potrzebuje w wielu aplikacjach, ale nie zbyt wiele osób jest zainteresowanych (lub powinno) budowaniem siebie.

Więcej Informacji

 362
Author: Chris McCauley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-09 01:58:08

Po pierwsze, Rack to dokładnie dwie rzeczy:

  • a webserver interface convention
  • klejnot

Rack-Interfejs Serwera Www

Podstawy racka to prosta konwencja. Każdy serwer WWW zgodny z rack zawsze wywoła metodę call na danym obiekcie i poda wynik tej metody. Rack określa dokładnie, jak ma wyglądać ta metoda wywołania i co ma zwrócić. To rack.

Let ' s give it prosta próba. Użyję WEBrick jako serwera zgodnego z rackiem, ale każdy z nich to zrobi. Stwórzmy prostą aplikację webową, która zwraca ciąg JSON. W tym celu utworzymy plik o nazwie config.ru. The config.ru zostanie automatycznie wywołana przez polecenie rackup gem, które po prostu uruchomi zawartość config.ru w serwerze zgodnym z rackiem. Dodajmy więc do config.ru plik:

class JSONServer
  def call(env)
    [200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
  end
end

map '/hello.json' do
  run JSONServer.new
end

Zgodnie z konwencją nasz serwer posiada metodę call, która akceptuje hash środowiska i zwraca tablicę z formą [status, headers, body] dla serwera WWW, który ma służyć. Wypróbujmy go, po prostu dzwoniąc do rackup. Domyślny serwer zgodny z rackiem, może WEBrick lub Kundel uruchomi się i natychmiast czeka na serwowanie żądań.

$ rackup
[2012-02-19 22:39:26] INFO  WEBrick 1.3.1
[2012-02-19 22:39:26] INFO  ruby 1.9.3 (2012-01-17) [x86_64-darwin11.2.0]
[2012-02-19 22:39:26] INFO  WEBrick::HTTPServer#start: pid=16121 port=9292

Przetestujmy nasz nowy serwer JSON przez curling lub odwiedzając url http://localhost:9292/hello.json i voila:

$ curl http://localhost:9292/hello.json
{ message: "Hello!" }
To działa. Świetnie! To podstawa każdego frameworka internetowego, czy to Rails czy Sinatra. W pewnym momencie zaimplementuj metodę wywołania, przejrzyj cały kod frameworka i na koniec zwróć odpowiedź w typowej formie [status, nagłówki, body].

W Ruby on Rails na przykład żądania rack trafiają do klasy ActionDispatch::Routing.Mapper, która wygląda tak:

module ActionDispatch
  module Routing
    class Mapper
      ...
      def initialize(app, constraints, request)
        @app, @constraints, @request = app, constraints, request
      end

      def matches?(env)
        req = @request.new(env)
        ...
        return true
      end

      def call(env)
        matches?(env) ? @app.call(env) : [ 404, {'X-Cascade' => 'pass'}, [] ]
      end
      ...
  end
end

Więc w zasadzie sprawdzanie szyn, zależne od skrótu env, jeśli jakaś trasa pasuje. Jeśli tak, to przekazuje hash env do aplikacji, aby obliczyć odpowiedź, w przeciwnym razie natychmiast odpowiada za pomocą 404. Więc każdy serwer WWW, który jest zgodny dzięki konwencji interfejsu rack jest w stanie obsłużyć w pełni wydmuchaną aplikację szyn.

Middleware

Rack wspiera również tworzenie warstw middleware. Zasadniczo przechwytywają żądanie, robią coś z nim i przekazują dalej. Jest to bardzo przydatne do wszechstronnych zadań.

Załóżmy, że chcemy dodać logowanie do naszego serwera JSON, który również mierzy, jak długo trwa żądanie. Możemy po prostu stworzyć middleware logger, który robi dokładnie to:

class RackLogger
  def initialize(app)
    @app = app
  end

  def call(env)
    @start = Time.now
    @status, @headers, @body = @app.call(env)
    @duration = ((Time.now - @start).to_f * 1000).round(2)

    puts "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} - Took: #{@duration} ms"
    [@status, @headers, @body]
  end
end

Kiedy zostanie utworzona, zapisuje sobie kopię rzeczywistej aplikacji rack. W naszym przypadku jest to przykład naszego serwera JSONServer. Rack automatycznie wywołuje metodę call na serwerze middleware i oczekuje z powrotem tablicy [status, headers, body], tak jak zwraca nasz jsonserver.

Tak więc w tym oprogramowaniu pośredniczącym pobierany jest punkt początkowy, następnie wykonywane jest rzeczywiste wywołanie serwera JSONServer za pomocą @app.call(env), następnie logger wypisuje wpis logowania i na koniec zwraca odpowiedź jako [@status, @headers, @body].

Aby nasze małe rackup.ru użyj tego middleware, Dodaj do niego use RackLogger w następujący sposób:

class JSONServer
  def call(env)
    [200, {"Content-Type" => "application/json"}, ['{ "message" : "Hello!" }']]
  end
end

class RackLogger
  def initialize(app)
    @app = app
  end

  def call(env)
    @start = Time.now
    @status, @headers, @body = @app.call(env)
    @duration = ((Time.now - @start).to_f * 1000).round(2)

    puts "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']} - Took: #{@duration} ms"
    [@status, @headers, @body]
  end
end

use RackLogger

map '/hello.json' do
  run JSONServer.new
end   

Uruchom ponownie serwer i voila, wyświetla log na każde żądanie. Rack pozwala na dodawanie wielu middlewares, które są wywoływane w kolejności, w jakiej są dodawane. To po prostu świetny sposób na dodanie funkcjonalności bez zmiany rdzenia aplikacji rack.

Regał-Klejnot

Chociaż rack-przede wszystkim-jest konwencją, to jest również klejnotem, który zapewnia dużą funkcjonalność. Jeden z nich, którego użyliśmy już na naszym serwerze JSON, Komenda rackup. Ale to nie wszystko! Rack gem zapewnia niewiele aplikacji do wielu zastosowań, takich jak serwowanie plików statycznych lub nawet całych katalogów. Zobaczmy, jak obsługujemy prosty plik, na przykład bardzo podstawowy plik HTML znajdujący się w htmls / index.html:
<!DOCTYPE HTML>
  <html>
  <head>
    <title>The Index</title>
  </head>

  <body>
    <p>Index Page</p>
  </body>
</html>

Być może chcemy podać ten plik z katalogu głównego, więc dodajmy do naszego config.ru:

map '/' do
  run Rack::File.new "htmls/index.html"
end

Jeśli odwiedzimy http://localhost:9292 widzimy nasz plik html doskonale renderowany. To było łatwe, prawda?

Dodajmy cały katalog plików javascript, tworząc kilka plików javascript w / javascripts i dodając do config.ru:

map '/javascripts' do
  run Rack::Directory.new "javascripts"
end

Uruchom ponownie serwer i odwiedź http://localhost:9292/javascript, a zobaczysz listę wszystkich plików javascript, które możesz teraz dołączyć prosto z dowolnego miejsca.

 78
Author: Thomas Fankhauser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-24 08:22:25

Miałem problem ze zrozumieniem Racka przez długi czas. W pełni zrozumiałem to dopiero po pracy nad stworzeniem tego miniaturowego serwera Ruby web server. Podzieliłam się swoimi spostrzeżeniami na temat Racka (w formie opowiadania) tutaj na moim blogu: http://gauravchande.com/what-is-rack-in-ruby-rails

Opinie są mile widziane.

 20
Author: Gaurav Chande,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-15 16:42:14

config.ru minimal runnable przykład

app = Proc.new do |env|
  [
    200,
    {
      'Content-Type' => 'text/plain'
    },
    ["main\n"]
  ]
end

class Middleware
  def initialize(app)
    @app = app
  end

  def call(env)
    @status, @headers, @body = @app.call(env)
    [@status, @headers, @body << "Middleware\n"]
  end
end

use(Middleware)

run(app)

Uruchom rackup i odwiedź localhost:9292. Wyjście to:

main
Middleware

Jest więc jasne, że Middleware zawija i wywołuje główną aplikację. Dlatego jest w stanie wstępnie przetworzyć żądanie i przetworzyć odpowiedź w dowolny sposób.

Jak wyjaśniono w: http://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack , Rails używa Rack middlewares do wielu swoich funkcjonalności, a Ty możesz też dodać własne z config.middleware.use metodami rodzinnymi.

Zaletą implementacji funkcjonalności w middleware jest to, że można ją ponownie wykorzystać na dowolnym frameworku Rack, a więc wszystkich głównych frameworkach Ruby, a nie tylko Rails.

 8
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-28 20:23:52

Co to jest Rack?

Rack zapewnia minimalny interfejs pomiędzy webserwerami obsługującymi frameworki Ruby i Ruby.

Używając Rack możesz napisać aplikację Rack.

Rack przekazuje Hash środowiskowy (Hash, zawarty w żądaniu HTTP od klienta, składający się z nagłówków podobnych do CGI) do aplikacji Rack, która może używać rzeczy zawartych w tym hashu do robienia czego chce.

Co to jest aplikacja Rack?

Aby korzystać z Rack, musisz dostarcza " app " - obiekt, który reaguje na metodę #call z parametrem hash środowiska (Zwykle zdefiniowanym jako env). #call musi zwrócić tablicę dokładnie trzech wartości:

  • kod statusu (np. '200'),
  • a Hash nagłówków ,
  • ciało odpowiedzi (które musi odpowiadać metodzie Ruby, each).

Możesz napisać aplikację Rack, która zwróci taką tablicę - zostanie ona odesłana do twojego klienta, przez Rack, wewnątrz odpowiedź (będzie to rzeczywiście instancja klasy Rack::Response [Kliknij, aby przejść do dokumentów]).

Bardzo Prosta Aplikacja Stojaka:

  • gem install rack
  • Utwórz config.ru plik-Rack wie, aby tego szukać.

Utworzymy małą aplikację Rack, która zwróci odpowiedź (instancję Rack::Response), której ciałem odpowiedzi jest tablica zawierająca Łańcuch znaków: "Hello, World!".

Odpalimy serwer lokalny używając polecenie rackup.

Odwiedzając odpowiedni port w naszej przeglądarce zobaczymy "Hello, World!"rendered in the viewport.

#./message_app.rb
class MessageApp
  def call(env)
    [200, {}, ['Hello, World!']]
  end
end

#./config.ru
require_relative './message_app'

run MessageApp.new

Uruchom serwer lokalny z rackup i odwiedź localhost: 9292 i powinieneś zobaczyć 'Hello, World!"rendered.

Nie jest to wyczerpujące wyjaśnienie, ale zasadniczo dzieje się tak, że Klient (przeglądarka) wysyła żądanie HTTP do Rack, za pośrednictwem lokalnego serwera, a Rack tworzy instancje MessageApp i uruchamia call, przekazywanie w środowisku Hasha jako parametru do metody (argument env).

Rack pobiera zwracaną wartość (tablicę) i używa jej do utworzenia instancji Rack::Response i wysyła ją z powrotem do Klienta. Przeglądarka używa magii aby wydrukować 'Hello, World! na ekran.

Nawiasem mówiąc, jeśli chcesz zobaczyć, jak wygląda hash środowiska, po prostu umieść puts env Pod def call(env).

Minimal jak to jest, to co napisałeś tutaj jest Rack podanie!

Dzięki temu, że aplikacja Rack wchodzi w interakcję z przychodzącym środowiskiem hash]}

W naszej małej aplikacji Rack, możemy wchodzić w interakcje z env hash (zobacz tutaj aby dowiedzieć się więcej o hash środowiska).

Zaimplementujemy możliwość wprowadzania przez użytkownika własnego ciągu zapytania do adresu URL, stąd ten łańcuch będzie obecny w żądaniu HTTP, zamkniętego jako wartość w jednej z par klucz / wartość haszu środowiska.

Nasza aplikacja Rack będzie uzyskaj dostęp do tego łańcucha zapytania z hash środowiska i wyślij go z powrotem do Klienta (w tym przypadku naszej przeglądarki) za pośrednictwem treści w odpowiedzi.

From the Rack docs on the Environment Hash: " QUERY_STRING: część adresu URL żądania, która następuje po ? jeśli w ogóle. Może być pusty, ale jest zawsze wymagane!"

#./message_app.rb
class MessageApp
  def call(env)
    message = env['QUERY_STRING']
    [200, {}, [message]]
  end
end

Teraz, rackup i odwiedzić localhost:9292?hello (?hello jako ciąg zapytania) i powinieneś zobaczyć "hello" renderowane w viewport.

Rack Middleware

Będziemy:

  • włóż kawałek Rack Middleware do naszej bazy kodowej-klasy: MessageSetter,
  • Environment hash trafi najpierw do tej klasy i zostanie przekazany jako parametr: env,
  • MessageSetter wstawi 'MESSAGE' klucz do skrótu env, jego wartość wynosi 'Hello, World!' jeśli env['QUERY_STRING'] jest pusta; env['QUERY_STRING'] jeśli nie,
  • w końcu powróci @app.call(env) - @app jako następna aplikacja w "stosie": MessageApp.

Po pierwsze, "Długa Ręka" wersja:

#./middleware/message_setter.rb
class MessageSetter
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['QUERY_STRING'].empty?
      env['MESSAGE'] = 'Hello, World!'
    else
      env['MESSAGE'] = env['QUERY_STRING']
    end
    @app.call(env)
  end
end

#./message_app.rb (same as before)
class MessageApp
  def call(env)
    message = env['QUERY_STRING']
    [200, {}, [message]]
  end
end

#config.ru
require_relative './message_app'
require_relative './middleware/message_setter'

app = Rack::Builder.new do
  use MessageSetter
  run MessageApp.new
end

run app

Z Rack::Builder docs widzimy, że Rack::Builder implementuje mały DSL do iteratywnego konstruowania aplikacji Rack. Oznacza to w zasadzie, że można zbudować "stos" składający się z jednego lub więcej Middlewares i "dolny poziom" aplikacji do wysyłki. Wszystkie wnioski trafiające do aplikacji niższego poziomu będą najpierw przetwarzane przez oprogramowanie pośredniczące.

#use określa oprogramowanie pośredniczące do użycia w stosie. Przyjmuje middleware jako kłótnia.

Rack Middleware musi:

  • mieć konstruktor, który jako parametr przyjmuje następną aplikację w stosie.
  • odpowiedź na metodę call, która przyjmuje jako parametr hash środowiska.

W naszym przypadku 'Middleware' to MessageSetter, 'konstruktor' to metoda MessageSetter initialize, 'Następna aplikacja' w stosie to MessageApp.

Więc tutaj, z powodu tego, co Rack::Builder robi pod maską, app argument MessageSetter'S initialize metoda jest MessageApp.

(zapoznaj się z powyższym, zanim przejdziesz dalej)

Dlatego każdy element oprogramowania pośredniczącego zasadniczo "przekazuje" istniejący hash środowiska do następnej aplikacji w łańcuchu - więc masz możliwość mutacji tego hasha środowiska wewnątrz oprogramowania pośredniczącego przed przekazaniem go do następnej aplikacji w stosie.

#run pobiera argument, który jest obiektem, który odpowiada na #call i zwraca odpowiedź Rack (an instancja Rack::Response).

Wnioski

Za pomocą Rack::Builder możesz konstruować łańcuchy elementów pośredniczących, a każde żądanie do Twojej aplikacji będzie przetwarzane przez każdą z nich, zanim ostatecznie zostanie przetworzone przez ostatni element w stosie(w naszym przypadku MessageApp). Jest to niezwykle przydatne, ponieważ oddziela różne etapy przetwarzania żądań. Jeśli chodzi o "oddzielenie obaw", nie może być dużo czystsze!

Można skonstruować 'request pipeline' składający się z kilku pośredników, które zajmują się takimi rzeczami jak:

  • uwierzytelnianie
  • autoryzacja
  • buforowanie
  • Dekoracja
  • [[69]}Monitorowanie Wydajności I Użytkowania [72]} W związku z tym, że nie jest to możliwe, nie jest to możliwe.]}

(powyżej punkty z innej odpowiedzi w tym wątku)

Często zobaczysz to w profesjonalnych aplikacjach Sinatra. Sinatra używa Racka! Zobacz tutaj po definicję tego, co Sinatra na!

Na koniec, nasz config.ru może być napisany w stylu krótkiej ręki, produkując dokładnie tę samą funkcjonalność (i to jest to, co zwykle zobaczysz):]}
require_relative './message_app'
require_relative './middleware/message_setter'

use MessageSetter
run MessageApp.new

I aby dokładniej pokazać, co robi MessageApp, Oto jego wersja "long-hand", która wyraźnie pokazuje, że #call tworzy nową instancję Rack::Response, z wymaganymi trzema argumentami.

class MessageApp
  def call(env)
    Rack::Response.new([env['MESSAGE']], 200, {})
  end
end

Przydatne linki

 7
Author: Yorkshireman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-12 01:15:51

Rack middleware to sposób na filtrowanie żądania i odpowiedzi pojawiających się w Twojej aplikacji. Komponent middleware znajduje się między Klientem a serwerem, przetwarzając przychodzące żądania i wychodzące odpowiedzi, ale to coś więcej niż interfejs, który może być używany do rozmowy z serwerem WWW. Służy do grupowania i porządkowania modułów, które są zazwyczaj klasami Ruby, oraz określania zależności między nimi. Moduł Rack middleware musi: - posiadać konstruktor, który jako parametr przyjmuje następną aplikację w stosie – odpowiedź na metodę "call", która jako parametr przyjmuje hash środowiska. Zwracaną wartością z tego wywołania jest tablica: kod stanu, hash środowiska i ciało odpowiedzi.

 6
Author: L.Cole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-11 14:41:30

Użyłem Rack middleware do rozwiązania kilku problemów:

  1. Przechwytywanie błędów JSON parse za pomocą niestandardowego oprogramowania pośredniczącego Rack i zwracanie ładnie sformatowanych komunikatów o błędach, gdy Klient przesyła uszkodzony JSON
  2. Kompresja treści poprzez Rack:: Deflater

W obu przypadkach było to dość eleganckie rozwiązanie.

 4
Author: djcp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-12 18:17:09

obraz przedstawiający stojak pomiędzy jednorożcem a szynami

Rack jest klejnotem, który zapewnia prosty interfejs do abstrakcyjnego żądania/odpowiedzi HTTP. Rack znajduje się pomiędzy frameworkami sieciowymi (Rails, Sinatra itp.) a serwerami sieciowymi (unicorn, puma) jako adapter. Z powyższego obrazu to sprawia, że unicorn server jest całkowicie niezależny od wiedzy o rails, a rails nie wie o unicorn. Jest to dobry przykład luźnego sprzężenia, rozdzielenie obaw .

Powyższy obrazek pochodzi z tej konferencji rails na racku https://youtu.be/3PnUV9QzB0g zalecam oglądanie go dla głębszego zrozumienia.

 4
Author: Vbp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-17 18:38:55

Rack-interfejs b / W Web & App Server

Rack jest pakietem Ruby, który zapewnia interfejs dla serwera www do komunikacji z aplikacją. Łatwo jest dodać komponenty middleware między serwerem WWW a aplikacją, aby zmodyfikować sposób zachowania żądania / odpowiedzi. Komponent middleware znajduje się między Klientem a serwerem, przetwarzając przychodzące żądania i wychodzące odpowiedzi.

W słowach laika, jest to w zasadzie tylko zestaw wytycznych, jak serwer i aplikacja Rails (lub jakakolwiek inna aplikacja Ruby) powinny ze sobą rozmawiać.

Aby użyć Rack, podaj "app": obiekt, który reaguje na metodę call, biorąc hash środowiska jako parametr i zwracając tablicę z trzema elementami:

  • Kod odpowiedzi HTTP
  • Hash nagłówków
  • ciało odpowiedzi , które musi odpowiedzieć na każde żądanie .

Aby uzyskać więcej wyjaśnień, możesz postępować zgodnie z poniżej linki.

1. https://rack.github.io/
2. https://redpanthers.co/rack-middleware/
3. https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware
4. https://guides.rubyonrails.org/rails_on_rack.html#resources

W rails mamy config.ru jako plik rack możesz uruchomić dowolny plik rack za pomocą polecenia rackup. Domyślnym portem jest 9292. Aby to przetestować, możesz po prostu uruchomić rackup w katalogu rails i zobaczyć wynik. Możesz również przypisać port, na którym chcesz go uruchomić. Polecenie uruchamiające plik rack na dowolnym porcie to

rackup -p PORT_NUMBER
 2
Author: V K Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-10 12:22:24