Šis vadovas eina per kiekvieną metodo iškvietimą,
reikalingą paleisti Ruby on Rails paketą numatytame Rails
programoje, išsamiai paaiškindamas kiekvieną dalį kelyje. Šiam
vadovui mes sutelksime dėmesį į tai, kas vyksta, kai vykdote bin/rails server
komandą, kad paleistumėte savo programą.
Pastaba: Šiame vadove keliose yra nuorodos į Rails arba Rails programą, nebent kitaip nurodyta.
Patarimas: Jei norite sekti kartu naršydami Rails šaltinio kodą, rekomenduojame naudoti t
klavišo junginį, kad atidarytumėte failų paieškos langą GitHub ir greitai rastumėte failus.
1 Paleidimas!
Pradėkime paleisti ir inicializuoti programą. Rails programa paprastai
paleidžiama vykdant bin/rails console
arba bin/rails server
.
1.1 bin/rails
Šis failas yra toks:
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative "../config/boot"
require "rails/commands"
APP_PATH
konstanta bus naudojama vėliau rails/commands
. Čia pateikiamas nuoroda į config/boot.rb
failą mūsų programoje, kuris atsakingas už Bundler įkėlimą ir jo konfigūraciją.
1.2 config/boot.rb
config/boot.rb
yra toks:
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require "bundler/setup" # Nustatyti Gemfile nurodytus paketus.
Standartinėje Rails programoje yra Gemfile
, kuriame nurodomos visos
programos priklausomybės. config/boot.rb
nustato
ENV['BUNDLE_GEMFILE']
reikšmę į šio failo vietą. Jei yra Gemfile
,
tada reikalingas bundler/setup
. Šis reikalavimas naudojamas, kad Bundler konfigūruotų paketų įkėlimo kelią.
1.3 rails/commands.rb
Kai config/boot.rb
baigia darbą, sekančias reikalingas failas yra
rails/commands
, kuris padeda išplėsti pseudonimus. Šiuo atveju
ARGV
masyve tiesiog yra server
, kuris bus perduotas:
require "rails/command"
aliases = {
"g" => "generate",
"d" => "destroy",
"c" => "console",
"s" => "server",
"db" => "dbconsole",
"r" => "runner",
"t" => "test"
}
command = ARGV.shift
command = aliases[command] || command
Rails::Command.invoke command, ARGV
Jei būtume naudoję s
vietoje server
, Rails būtų naudojęs čia apibrėžtus aliases
norėdamas rasti atitinkamą komandą.
1.4 rails/command.rb
Kai įvedama Rails komanda, invoke
bando rasti komandą pagal nurodytą
vietą ir vykdo komandą, jei ji yra rasta.
Jei Rails nepripažįsta komandos, ji perduoda valdymą Rake komandai su tuo pačiu pavadinimu.
Kaip matyti, Rails::Command
automatiškai rodo pagalbos išvestį, jei namespace
yra tuščias.
module Rails
module Command
class << self
def invoke(full_namespace, args = [], **config)
namespace = full_namespace = full_namespace.to_s
if char = namespace =~ /:(\w+)$/
command_name, namespace = $1, namespace.slice(0, char)
else
command_name = namespace
end
command_name, namespace = "help", "help" if command_name.blank? || HELP_MAPPINGS.include?(command_name)
command_name, namespace = "version", "version" if %w( -v --version ).include?(command_name)
command = find_by_namespace(namespace, command_name)
if command && command.all_commands[command_name]
command.perform(command_name, args, config)
else
find_by_namespace("rake").perform(full_namespace, args, config)
end
end
end
end
end
Su server
komanda, Rails toliau vykdo šį kodą:
module Rails
module Command
class ServerCommand < Base # :nodoc:
def perform
extract_environment_option_from_argument
set_application_directory!
prepare_restart
Rails::Server.new(server_options).tap do |server|
# Require application after server sets environment to propagate
# the --environment option.
require APP_PATH
Dir.chdir(Rails.application.root)
if server.serveable?
print_boot_information(server.server, server.served_url)
after_stop_callback = -> { say "Exiting" unless options[:daemon] }
server.start(after_stop_callback)
else
say rack_server_suggestion(using)
end
end
end
end
end
end
Šis failas pakeis į Rails šakninį katalogą (kelias du katalogus aukštyn
nuo APP_PATH
, kuris rodo į config/application.rb
), bet tik jei
config.ru
failas nerastas. Tada paleidžiama Rails::Server
klasė.
1.5 actionpack/lib/action_dispatch.rb
Action Dispatch yra Rails karkaso maršrutizavimo komponentas. Jis prideda funkcionalumą, tokią kaip maršrutizavimas, sesija ir bendrosios tarpinės programinės įrangos.
1.6 rails/commands/server/server_command.rb
Rails::Server
klasė yra apibrėžiama šiame faile paveldinti iš
Rack::Server
. Kai yra iškviesta Rails::Server.new
, tai iškviečia initialize
metodą rails/commands/server/server_command.rb
faile:
module Rails
class Server < ::Rack::Server
def initialize(options = nil)
@default_options = options || {}
super(@default_options)
set_environment
end
end
end
Pirma, iškviečiamas super
, kuris iškviečia initialize
metodą Rack::Server
klasėje.
1.7 Rack: lib/rack/server.rb
Rack::Server
klasė atsakinga už bendrą serverio sąsają visoms Rack pagrindinėms aplikacijoms, kurios dabar yra dalis iš Rails.
initialize
metodas Rack::Server
klasėje tiesiog nustato keletą kintamųjų:
module Rack
class Server
def initialize(options = nil)
@ignore_options = []
if options
@use_default_options = false
@options = options
@app = options[:app] if options[:app]
else
argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
@use_default_options = true
@options = parse_options(argv)
end
end
end
end
Šiuo atveju, Rails::Command::ServerCommand#server_options
metodo grąžinimo reikšmė bus priskirta options
kintamajam.
Kai vykdomos eilutės if sąlygoje, bus nustatyti keletas objekto kintamieji.
server_options
metodas Rails::Command::ServerCommand
klasėje apibrėžtas taip:
module Rails
module Command
class ServerCommand
no_commands do
def server_options
{
user_supplied_options: user_supplied_options,
server: using,
log_stdout: log_to_stdout?,
Port: port,
Host: host,
DoNotReverseLookup: true,
config: options[:config],
environment: environment,
daemonize: options[:daemon],
pid: pid,
caching: options[:dev_caching],
restart_cmd: restart_command,
early_hints: early_hints
}
end
end
end
end
end
Reikšmė bus priskirta objekto kintamajam @options
.
Baigus super
vykdymą Rack::Server
klasėje, grįžtama į rails/commands/server/server_command.rb
failą. Šiuo metu, set_environment
metodas yra iškviestas Rails::Server
objekto kontekste.
module Rails
module Server
def set_environment
ENV["RAILS_ENV"] ||= options[:environment]
end
end
end
Baigus initialize
vykdymą, grįžtama į serverio komandą, kurioje yra reikalaujamas APP_PATH
(kuris buvo nustatytas anksčiau).
1.8 config/application
Kai vykdoma require APP_PATH
, įkeliamas config/application.rb
failas (atminkite, kad APP_PATH
yra apibrėžtas bin/rails
faile). Šis failas yra jūsų aplikacijoje ir jį galite keisti pagal savo poreikius.
1.9 Rails::Server#start
Baigus config/application
įkėlimą, iškviečiamas server.start
metodas. Šis metodas apibrėžtas taip:
module Rails
class Server < ::Rack::Server
def start(after_stop_callback = nil)
trap(:INT) { exit }
create_tmp_directories
setup_dev_caching
log_to_stdout if options[:log_stdout]
super()
# ...
end
private
def setup_dev_caching
if options[:environment] == "development"
Rails::DevCaching.enable_by_argument(options[:caching])
end
end
def create_tmp_directories
%w(cache pids sockets).each do |dir_to_make|
FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make))
end
end
def log_to_stdout
wrapped_app # touch the app so the logger is set up
console = ActiveSupport::Logger.new(STDOUT)
console.formatter = Rails.logger.formatter
console.level = Rails.logger.level
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
end
end
end
end
Šis metodas sukuria INT
signalų gaudyklą, todėl jei nutraukiate serverį naudodami CTRL-C
, procesas bus baigtas.
Kaip matome iš kodo čia, jis sukuria tmp/cache
, tmp/pids
ir tmp/sockets
direktorijas. Tada, jei bin/rails server
yra iškviestas su --dev-caching
parametru, įjungiamas kešavimas vystymosi aplinkoje. Galiausiai, jis iškviečia wrapped_app
metodą, kuris yra atsakingas už Rack aplikacijos kūrimą, prieš sukurdamas ir priskirdamas ActiveSupport::Logger
objektą.
super
metodas iškviečia Rack::Server.start
, kuris pradeda savo apibrėžimą taip:
module Rack
class Server
def start(&blk)
if options[:warn]
$-w = true
end
if includes = options[:include]
$LOAD_PATH.unshift(*includes)
end
if library = options[:require]
require library
end
if options[:debug]
$DEBUG = true
require "pp"
p options[:server]
pp wrapped_app
pp app
end
check_pid! if options[:pid]
# Touch the wrapped app, so that the config.ru is loaded before
# daemonization (i.e. before chdir, etc).
handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
wrapped_app
end
daemonize_app if options[:daemonize]
write_pid if options[:pid]
trap(:INT) do
if server.respond_to?(:shutdown)
server.shutdown
else
exit
end
end
server.run wrapped_app, options, &blk
end
end
end
Įdomus dalykas Rails aplikacijai yra paskutinė eilutė, server.run
. Čia vėl susiduriame su wrapped_app
metodu, kurį šį kartą išnagrinėsime išsamiau (nors jis jau buvo vykdytas anksčiau ir tuo pačiu metu buvo memoized).
module Rack
class Server
def wrapped_app
@wrapped_app ||= build_app app
end
end
end
app
metodas čia yra apibrėžtas taip:
module Rack
class Server
def app
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
end
# ...
private
def build_app_and_options_from_config
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
@options.merge!(options) { |key, old, new| old }
app
end
def build_app_from_string
Rack::Builder.new_from_string(self.options[:builder])
end
end
end
options[:config]
reikšmė pagal nutylėjimą yra config.ru
, kuriame yra šis kodas:
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
run Rails.application
Rack::Builder.parse_file
metodas čia ima šio config.ru
failo turinį ir jį analizuoja naudodamas šį kodą:
module Rack
class Builder
def self.load_file(path, opts = Server::Options.new)
# ...
app = new_from_string cfgfile, config
# ...
end
# ...
def self.new_from_string(builder_script, file = "(rackup)")
eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
TOPLEVEL_BINDING, file, 0
end
end
end
Rack::Builder
klasės initialize
metodas priims bloką ir jį vykdys Rack::Builder
objekte.
Tai yra vieta, kurioje dauguma Rails inicializavimo procesų vyksta.
Pirmiausia vykdoma require
eilutė config.ru
faile, skirta config/environment.rb
failui:
require_relative "config/environment"
1.10 config/environment.rb
Šis failas yra bendras failas, kurį reikalauja config.ru
(bin/rails server
) ir Passenger. Čia susitinka šie du būdai paleisti serverį; viskas iki šios vietos buvo susiję su Rack ir Rails paruošimu.
Šis failas prasideda nuo config/application.rb
failo reikalavimo:
require_relative "application"
1.11 config/application.rb
Šis failas reikalauja config/boot.rb
failo:
require_relative "boot"
Tačiau tik jei jis dar nebuvo reikalaujamas anksčiau, kas būtų atvejis bin/rails server
,
bet nebūtų atvejis su Passenger.
Tada prasideda smagumas!
2 Įkeliant Rails
Kitas config/application.rb
eilutė yra:
require "rails/all"
2.1 railties/lib/rails/all.rb
Šis failas atsakingas už visų atskirų Rails karkasų reikalavimą:
require "rails"
%w(
active_record/railtie
active_storage/engine
action_controller/railtie
action_view/railtie
action_mailer/railtie
active_job/railtie
action_cable/engine
action_mailbox/engine
action_text/engine
rails/test_unit/railtie
).each do |railtie|
begin
require railtie
rescue LoadError
end
end
Čia įkeliami visi Rails karkasai ir taip padaromi prieinami aplikacijai. Mes nesigilinsime į tai, kas vyksta kiekvienoje iš tų karkasų, bet jūsų raginama tai išbandyti ir tyrinėti patiems.
Šiuo metu tiesiog turėkite omenyje, kad bendros funkcijos, pvz., Rails varikliai, I18n ir Rails konfigūracija, čia yra apibrėžiami.
2.2 Grįžtame prie config/environment.rb
Likusi config/application.rb
dalis apibrėžia konfigūraciją
Rails::Application
, kuri bus naudojama, kai aplikacija bus visiškai
inicializuota. Kai config/application.rb
baigia įkelti Rails ir apibrėžia
aplikacijos vardų erdvę, grįžtame prie config/environment.rb
. Čia
aplikacija yra inicializuojama su Rails.application.initialize!
, kas yra
apibrėžta rails/application.rb
faile.
2.3 railties/lib/rails/application.rb
initialize!
metodas atrodo taip:
def initialize!(group = :default) # :nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
Aplikaciją galite inicializuoti tik vieną kartą. Railtie inicializatoriai
yra vykdomi per run_initializers
metodą, kuris yra apibrėžtas
railties/lib/rails/initializable.rb
faile:
def run_initializers(group = :default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort_each do |initializer|
initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
Pats run_initializers
kodas yra sudėtingas. Tai, ką Rails čia daro, yra
peržiūri visus klasės paveldėjimus, ieškodamas tokių, kurie atsako į
initializers
metodą. Tada jie yra rūšiuojami pagal pavadinimą ir vykdomi.
Pavyzdžiui, Engine
klasė padaro visus variklius prieinamus,
teikdama jiems initializers
metodą.
Rails::Application
klasė, kaip apibrėžta railties/lib/rails/application.rb
faile, apibrėžia bootstrap
, railtie
ir finisher
inicializatorius. bootstrap
inicializatoriai
paruošia aplikaciją (pvz., inicializuoja žurnalo įrašyklę), o finisher
inicializatoriai (pvz., sukuria tarpinės programinės įrangos paketą) yra vykdomi paskutiniai. railtie
inicializatoriai yra inicializatoriai, kurie buvo apibrėžti Rails::Application
paties ir yra vykdomi tarp bootstrap
ir finishers
.
PASTABA: Nesusipainiokite bendrų Railtie inicializatorių su load_config_initializers
inicializatoriaus atveju arba su tuo susijusiais konfigūracijos inicializatoriais config/initializers
aplanke.
Tai padarius, grįžtame prie Rack::Server
.
2.4 Rack: lib/rack/server.rb
Paskutinį kartą palikome, kai buvo apibrėžiamas app
metodas:
module Rack
class Server
def app
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
end
# ...
private
def build_app_and_options_from_config
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
@options.merge!(options) { |key, old, new| old }
app
end
def build_app_from_string
Rack::Builder.new_from_string(self.options[:builder])
end
end
end
Šiuo metu app
yra pats Rails aplikacija (tarpinė programinė įranga), ir kas
vyksta toliau, tai yra, kad Rack iškvies visus pateiktus tarpinius programinės įrangos paketus:
module Rack
class Server
private
def build_app(app)
middleware[options[:environment]].reverse_each do |middleware|
middleware = middleware.call(self) if middleware.respond_to?(:call)
next unless middleware
klass, *args = middleware
app = klass.new(app, *args)
end
app
end
end
end
Atminkite, kad build_app
buvo iškviestas (naudojant wrapped_app
) paskutinėje Rack::Server#start
eilutėje.
Taip tai atrodė, kai palikome:
server.run wrapped_app, options, &blk
Šiuo metu server.run
įgyvendinimas priklausys nuo
naudojamo serverio. Pavyzdžiui, jei naudojate Puma, čia yra,
kaip atrodytų run
metodas:
module Rack
module Handler
module Puma
# ...
def self.run(app, options = {})
conf = self.config(app, options)
events = options.delete(:Silent) ? ::Puma::Events.strings : ::Puma::Events.stdio
launcher = ::Puma::Launcher.new(conf, events: events)
yield launcher if block_given?
begin
launcher.run
rescue Interrupt
puts "* Gracefully stopping, waiting for requests to finish"
launcher.stop
puts "* Goodbye!"
end
end
# ...
end
end
end
Mes neįsijungsime į serverio konfigūraciją patį, bet tai yra paskutinis mūsų kelionės per Rails inicializavimo procesą gabalas.
Šis aukšto lygio apžvalga padės jums suprasti, kada ir kaip vykdomas jūsų kodas ir apskritai tapti geresniu Rails programuotoju. Jei vis tiek norite sužinoti daugiau, Rails šaltinio kodas pats tikriausiai yra geriausias kitas žingsnis.
Atsiliepimai
Jūs esate skatinami padėti pagerinti šio vadovo kokybę.
Prašome prisidėti, jei pastebite rašybos klaidų ar faktinių klaidų. Norėdami pradėti, galite perskaityti mūsų dokumentacijos prisidėjimo skyrių.
Taip pat gali būti nepilnos informacijos arba informacijos, kuri nėra atnaujinta. Prašome pridėti bet kokią trūkstamą dokumentaciją pagrindiniam. Patikrinkite Edge vadovus pirmiausia, ar problemas jau išspręsta arba ne pagrindinėje šakoje. Patikrinkite Ruby on Rails vadovų gaires dėl stiliaus ir konvencijų.
Jei dėl kokios nors priežasties pastebite kažką, ką reikia ištaisyti, bet negalite patys tai pataisyti, prašome pranešti apie problemą.
Ir galiausiai, bet ne mažiau svarbu, bet koks diskusijos dėl Ruby on Rails dokumentacijos yra labai laukiamos oficialiame Ruby on Rails forume.