The Rails Boot Process
Noria, Xavier
Rails ships as a number of components, Active Record, Active Support, ..., largely independent of each other, but somehow something orchestrates them and presents a unified view of the system. Then we have config/boot.rb, config/application.rb... what do they do? Application initializers, environment configuration, what runs when? Understanding how that works becomes an inflection point in any Rails programmer that goes through it. You go from that cloudy idea of an initialization that sets things up for a certain definition of "things", to a well-understood process.
 We are going to see a talk about the Rails boot process and I would like to explain before the goals of this talk. So in this talk, we are going to see a few things related to this topic. For instance, if you open the config directory, there are a number of files that we normally never touch that are generated, like this config boot, convic environment, and so we are going to see what they do. And Rails components in general can work independently of Rails. So Active Support, for instance, is a library that you know you can use in Ruby script, you know, that is not running inside the Rails application. Also for instance, you can use Active Record outside Rails. You can have like a regular Ruby script using Active Record connecting to everything, you know, you have everything. But somehow, magically, you know, you launch a Rails application and all these independent components are, you know, somehow organized for you and seamlessly you use them, you know, and there is nothing that the programmer has to do to get these things working together. And we are going to see how that works. And you know, the final goal is to understand more or less what happens when. Okay? I say more or less because there is a lot happening, but we are going to have a good sense of what happens when. And for this talk, we are going to have to take into account a few things. First, the approach of the talk is thought for Rails parameters, all right? So for instance, it's not going to be like, you know, a walkthrough of, you know, of code and code and code and see the rune path of these things. So we are going to see code, but it's not a walkthrough. So with this talk, I have tried to explain what I would like to know as a Rails parameter about the root process, the boot process, okay? And it is something that I would like an, an any guide to cover, you know, that kind of information. In the boot process, we have rail ties and we have engines, but this is not a talk about rail ties and engines. We are going to see what they are, but that's, that's a topic for, for the whole talk, okay? So we are going to see only what is needed for this talk about rail ties and engines. Therefore, we are going to see some code snippets, but they are going to be, like, heavily, heavily edited. So I, I have not tried, even tried that, that you want this, so that the, the slides makes clear this has been edited, you know, with ellipse, with ellipses or something like that. We put, like, a big warning and in general, the code we are going to see if you open the real file is going to have more stuff, okay? But there's a lot going on and I tried to select and, you know, uncut everything out that was not relevant to the, to the topic we are talking about. And finally, we are going to ignore spring, you know, so the boot process assuming that, no, no, no, no. This is the boot process, you know, the vanilla thing, okay, without, without additions. All right. So normally when, when you, when you think about booting rails, you, you have a server in mind, okay? You, you, you launch the application, you launch the server, you can, you are able to, to serve requests and everything. But there are more things that, that boot rails. So for instance, if you run the console, you know that somehow you have everything in the application available in the console, right? Also runner, if you run, you know, if you pass runner a string or, or a filename, it gets executed in the context of the application. So somehow the application has been booted for, you know, in order to run these commands. Runner indeed is a command that I love, I, I believe I run this command every day. So it allows you to run something quickly instead of launching the console and then control D and that kind of thing. You just, you know, runner something and indeed to understand the rails, the, the, the rails initialization, runner one, which is execute the program that has a literal one, you know, it's something that I do often, you know. So that's the minimum thing, the minimum thing, Rails runner one, the minimum thing that, you know, loads what it has to load, does what it has to do and then there's no more side effects except a blockchain one, which is not allowed. And also in some great tasks, you know, that you have also the environment load. So booting the application means being ready to serve all these kind of things. All right, so let's open bin rails. Okay. This is a file that is generated, but in any, at least modern Rails application. And we have here config boot, we load config boot and then it doesn't require something. Okay. If you open bin rake, you will see that it loads config boot and then does a stuff related to rake. Okay. So these both, these both files start loading config boot. That's the first thing. And if you open config boot, you will see that is basically doing bundler setup. Okay. Bundler setup configures the load paths so the application is able to require the gems that are in the gem file with, you know, with all the constraints and everything and is not able to load gems that are outside that thing. Okay. So bundler setup tricks load path and I don't know, all is needed so that that is going to work. Then if you open config rule, which is what you execute when you launch a server, you will see that it requires config environment. Okay. And then does something. Config environment is another important, important file. It loads application and this is config application RV, which is the first file we normally, you know, working as a programmer, that's the kind of the first thing, you know, config application RV is where stuff starts, where you can config, I don't know, time zone, that kind of stuff. Okay. So that's the file that is being referenced here. And then very important, it runs Rails application in italyse. And this is the magic. So in italyse, this method is the one that runs all the initializations. Up to now, we are like setting things up, you know, to be able to do this. And this is config application RV, which loads Rails all and then executes bundler require with the groups that are relevant to that execution. Okay. So Rails all, we are not going to see, we are going to see Rails all later. Okay. Forget about it for a moment. But the point here is that we are doing bundle require. At this point is when the gem dependencies are loaded, okay, unless you opt out, okay, at this point. And after that, we evaluate the class that defines the application itself, which is, you know, this thing that is named after, you know, what you pass to the new command, that kind of thing. Okay. So the presentation is organized in a few blocks. And we are going to be a bit like a roller coaster. Okay. So we are going to dive a little bit in something and then I'll leave it up, doing some summaries. Okay. So this is the summary of what we have seen up to this point. So define load paths. We have the gem dependencies ready. Then load Rails all, which is something that is going to be seen later. Then we actually load the dependencies, define application class, run initialize. That's like the script, you know, that's the order in which things run in at this point. And it's initialize that does, you know, the proper Rails boot process. Okay. All right. Rails-RailTie. So Rails-RailTie is a class that provides a number of things so that extensions and, you know, are able to hook into this process. For instance, it provides hooks to run code when you launch a console, when you launch the runner command, you know. So you can say as a gem, you can say, hey, if I am loaded in a Rails application and the console is launched, please call this code. Okay. So we may have, you know, a series of blocks like this that are scheduled to run at that point. Then you have the ability to define custom configuration points. Okay. So when you see, like, for instance, config.activerecord.something, you know, a RailTie, we're going to see later that ActiveRecord is a RailTie, allows you to define configuration points so that applications are able to, you know, to express the configuration they want. And also very important, they have the ability to declare code to be executed during boot. So these are called initializers. Okay. So hooks, configuration points, and the ability to declare. So Rails can declare that I want to run something when the inedulation happens, which is something I don't know. Okay. RailTies are defined by suppressing this class, this very class. And Rails knows which RailTies are defined because there's an inherited hook, you know, that when Rails, RailTie is subclassed, there's an inherited hook that say, hey, I have been subclassed and that by definition is a RailTie. Okay. Well, there's a technical thing about some special subclasses that I ignored, but that's the idea. So let's see an example. Okay. So this is, for instance, a RailTie or FactoryGal. And this initializer thing with a block is, FactoryGal is declaring when the application is initialized and I don't know when that is, you know, but when it happens, you've got to run this code. So for instance, FactoryGal at this point knows that Rails root is already defined. Okay. That's a contract. You know you can assume that. Okay. And in this case, FactoryGal is setting up some factory paths or something like that. Okay. So the way FactoryGal, so FactoryGal needs to define some paths that depend on the Rails application. And the way to do that in an integrated way with Rails is to define a RailTie and say, okay, when you are booting, call me and I will, I will configure myself. All right. So Rails components are integrated into the framework using RailTies. For instance, this is the RailTie of ActiveRecord. ActiveRecord defines a RailTie to integrate into the framework. In this case, for instance, this is an example. This is one of, this is the hook that tells Rails to run this code if the console is launched. Okay. So if the console is launched, if it's launched in sandbox mode, which is a mode that starts a transaction and rollbacks a transaction when the console, when the session is over, okay, load some code, I have not copied here, okay, load whatever you need to support this thing. And for instance, then you have, you know, that recently in the console, you get, you get the SQL logins in, you know, there. So there's code that says, okay, unlock to standard error. All right. So that's the way ActiveRecord integrates into Rails by defining a RailTie that does this and does a lot of other things, all right? Okay. For instance, this is from ActionDispatch. And we are seeing here an example of configuration. We saw before an example of hooking into the console. Now we see an example with configuration. So for instance, this is the way ActionDispatch defines a configuration point called tld underscore length and it gives this configuration point a default, which is one, okay? This is from ActiveSupport. And this is another Initializer. We saw an Initializer for FactoryGal. We are now seeing an Initializer for ActiveSupport. And we do not need to understand this code, but it's basically taking the time zone that the application has configured and setting whatever ActiveSupport needs to set up to take into account that configuration point. Okay. So that's what Rails all does. Rails all is just, you know, it just loads all the Rails ties of the different components in Rails. So application.rb loads this file. This file is just looping and loads everything, all right? And as a side effect of loading these things, we have first that Rails knows that RailTie has been suplaced. So we are able to list the RailTies that have been loaded. And also as a side effect of loading these, we have the configuration points, the declarations of the Initializer. So it's like a setup, okay? And that's the way the components work seamlessly in a Rails application. So the application, in reality, well, as a rule of thumb, let's say, maybe it's not 100% in all cases, but as a rule of thumb, this is, I don't know, I like to remind this design. So Rails is not coupled to the components. Rails is kind of agnostic to most of them, all right? So Rails does not have in the Initialization process anything that hardcodes the stuff to integrate the components. It goes the other way around. So the RailTies are loaded, and the configuration points are the interface between Rails and these components, okay? So ActiveRecord just loads and say, hey, call me the console, please run this Initializer, blah, blah, blah, blah, blah, okay? And the same for the rest of Rails components. And the RailTies, so are the components that know that they are living in a pattern application, okay? That's the way they integrate. So Rails does not hardcode in general anything about ActiveRecord, that kind of thing. Rails just exposes a number of configuration points, ActiveRecord loads, takes the configuration points that it needs to set up itself, and you know, you are set, okay? That's the idea. So Avonilla Rails application has 15 RailTies, which are these ones, okay? So you see, everyone that needs to integrate with all these processes has to define a RailTie. All right. Next block, lazy loading. So in general, so example of heavily edited code, this is ActiveRecord, which has a lot of things, okay? All right. So in general, if you open like the root file of the Rails components, you will see a lot of autoloads like this one, okay? This is the autoload of Ruby. Yeah, so Rails redefines because autoload in Ruby needs, you know, the constant and then it needs a path, all right? But when you follow naming conventions for the files and you write this thing three times, so the reaction is to write something that automates this using the convention. So modules that, this is the Ruby autoload, not the Rails autoload of constants, okay? So in general, when you boot, Rails tries to be as lazy as possible loading things, so you have the, you know, the minimal things to do when you boot. One of them is setting autoloads for, you know, this is the ActiveRecord, is the name space, so ActiveRecord base, ActiveRecord, I don't know, whatever, is going to be autoload. So it's not going to be ActiveRecord base, it's not going to be required on boot. It's going to be required when it's needed, you know? And that's thanks to autoload. So since things are going to be loaded only when needed, and there's code that needs to know, hey, have you loaded already ActiveRecord, for instance, to include something, Net of Record Base or whatever, there's this utility which is ActiveSupport on load. So for instance, in the ActiveRecord Rayty, we have to set up the logger of ActiveRecord. And the Initializer does not go straight away, you know, assigning the logger. Because the way to do this orderly is you declare that when ActiveRecord is loaded, then please set the logger with, you know, the block that I am passing here. Okay? So that's the way, you know, to defer as much as possible things in order to have as a boot process as lightweight as possible. And at the end of ActiveRecord base, at the end of ActiveRecord base, which is what ActiveRecord considers to be, you know, loading ActiveRecord, you know, by definition is evaluating this file, it says, room load hooks for ActiveRecord. Okay? So when this file is evaluated, all the, you know, the class is defined. And at the bottom of the file, you have this line. And then everything that was, you know, scheduled to be run when ActiveRecord loads is going to be, is going to be run at this point. Okay. Next block is Rails Engine. Rails Engine is a subclass of, of Rails ties. Okay? Of Rails Rails. They are defined as well. So Rails were defined by subclassing Rails Rails and engines are defined by subclassing Rails Engine. So it's the same, the same kind of thing. Okay? And what is an engine? So this, this would be like one, two, three talks. But just, you know, so just to get the idea of what it is, first it heritage everything from Rails, Rails. So always, always, we, we saw before about console, runner, you know, hooks, initializers, config points, that's all available here. But it's like a super set. You can do more things with an engine. So for instance, you can, you know, you, you can define controllers, models, that kind of thing. You have initializers as well, assets, you know, a bunch of things. So it's, it's closer to like, you know, unless you are able to define like a subset of an application, that's the idea for an engine. Okay? So engines have predefined some configuration points and also some initializers. All right? So just by subclassing engine, you got some configuration and some initializers for starters. So this is the one that are inherited. So when you define an engine subclassing Rails engine, you get this kind of thing. So you're going to set the load path of the engine. Okay? So adding your own lead directory or whatever, you know, to APP models, whatever, to the load path that is already set. Auto load path, routing paths, locale, a number of things. Okay? So it is not important to, to follow every single step of this, you know, it's maybe too detailed, but just, you know, to give an idea of the kind of things that, that you inherit from an engine. View paths, load environment config is the, these are initializers. This is the initializer that runs whatever you have in config environments, develop config environments, productionary, whatever. And then some other paths. Then you load config initializers, all right, disorder. And then there's a technical hook engines black point that says you've, at this point, you have already run a number of things. If you are interested in hooking into this, you can, all right? So initializers by default go like in chain, but you can say this has to run before this or the initializer or this has to run after that one. And there are a number of technical points in order to, to be able to do that. And a vanilla rage application, which is like rage new, you know, what, what, what do we get with rage new? There are four engines. So this, this four, okay? Okay. Action cable is an engine. It has an engine. So the rest of rage components have rail ties because with a rail tie is, is enough. What they have to do on boot. And actual cables has some assets. And that's the, that's the reason it, it is an engine. All right. And we, we are arriving to rage application, which is a subclass of engines. So look at this hierarchy. So the base thing is a rail tie. Then we have an engine and an application is a subclass of engines. So you know, the application is like a particular case of all this design. Okay. Beautiful. I think it's beautiful. All right. So they are defined by subclassing. And that, that's what you do in config application or B. If you remember, you have your application subclassing, race application. That's exactly what that file is doing. So the application is a, indeed is a singleton. You know, there's one, there's just one instance of that class and you can access that instance using race dot application, which is a method. And when the singleton is instantiate, you, you get a hook, call it before configuration. That's also just something that is fired. And if you're in a, in a rail tie, for instance, you say config dot before configuration, execute something is going to be executed at this point, which is just when the application is just, you know, you instantly, it got instantiate, you get this code called. Okay. So application execute for groups of initializers, for groups. It's organized this way. First you have the ones inherited from race engine. Okay. Race engine have some pre-configured ones. So those ones you inherit, therefore they are going to be executed. Then there's a bootstrap group that does like super basic things like setting up paths and that kind of thing. And we have the initializers of all the rail ties and engines that the application has load. Okay. And the way this is load is because we have a bundle require in config application. So if you have an extension, a gem or something implementing a rail tie or an engine, so what happens is that when bundle require loads that gem, that gem, you know, at that point defines the rail tie or the engine so that is, you know, so that the application knows about the existence of this thing. And then there's a finishes group that does, you know, some training stuff. So the bootstrap group, for instance, the first one is a technical hook as well. Then for instance, we load active support. So active support, that's not something optional. All, you know, the whole rails uses active support. Okay. So straight away, you, this one is hard code. This one is loaded. Okay. Yeah. So this loads active support all, which brings you everything in active support unless there's a configuration point which is config active support bear, which says instead of loading everything, just load whatever the application, I mean, whatever rails needs, you know, to run. And this light means that we are finishing. No? All right. I saw a change. Okay. Okay. Fine. Yeah. So you are able to load, you know, the minimum of active support. Okay. And that said, I have never seen this one used. So, but we have it there. Then eager load, you initialize the logger. This is the bootstrap log, the bootstrap group. Okay. So you initialize the logger, the cache, the way constant auto loading loads things which can be load or require depending on the environment or configuration. And then there's a before initialize hook, details, too much details. Okay. There are a number of things that are going on just having a look. And then rail ties and engines in a vanilla rails application have 94 initializers declared. Okay. It's too much. So then we have the finisher group. Okay. So things more or less, you can think that they run more or less in order except that the before and after things that are, you know, when you declare a relation, you can say before this and after this, you know, unless you have defined something, you can more or less think that they go in order. Okay. So yeah, a number of things. The finisher group does a number of things. Configure, sleep templates in case generators need to load things from here. Yeah, this second one is technical. Then this one is defining, you know, you know that if you go in development mode to rails info, you get some pages there. And if you go to the home, you get this new shiny thing, you know, in Rails 5. So the way that works, if you go to config routes, that's not in config routes, so how is that served? All right. So the routes are defined here. Those ones are defined here. You build the middleware stack at this point. So we are kind of already late. Okay. You have to think we are already, most of the things are done at this point. Well, you define main app, which is something for engines. Doesn't matter. To prepare blocks, important is a block that are run, you know, in certain, certain, you know, certain points of the run time. And eager load is important. By default in production, you eager load the application. And then there's another technical hook, which is the finisher hook that fires another, you know, another event, which is after initializing case you have to do something after this has run. All right. And a number of things that are too detailed maybe. Well, the second one loads the routes. This one is important. Okay. But there are a number of things in this finisher group going on. Okay. So once everything has been declared and we have everything load, you know, there's a topological sort going on here. So an etiolizer have an after, before topological sort, if someone does not know. Similarly if you have things that have an order, a relative order declared, like I have to run at some point, but make sure it's before that thing. Or I have to run at some point, but make sure it's after that other thing. Okay. So a topological sort is getting this linear in a way that respects these relative constraints. Okay. So if you said you need to run before that thing, you are guaranteed that you are going to run before that thing. Okay. Maybe not immediately before. It doesn't matter. So the constraint is relative. Okay. So maybe not just before, maybe two before. I don't know. It depends on the other things that have said that need to be run before that hook. Okay. So that's the idea in any case, we ordered the etiolizers to be run the way they have declared to be run. So at this shag one, we have 124 etiolizers. There's a lot going on. Okay. Because everything, you know, this is designed so that everything that needs to happen at boot is going to be generally happening in an etiolizer. So there's a lot of things, 124. And I have listed all of them. So if you get then a PDF or we see the video, we have them at least, you know, as a reference. This is not like public interface. This is not something Rails is telling you these are going to exist. You can, you know, you can assume that all of these 124 are going to exist in other releases or things like that. But anyway, just for the sake of the presentation, these are the ones I am just going to pass the slides because, you know, there's no point in going one by one. But you know, you see, we have setting load paths here, then out to load paths, you know, and there are like, all right. So yeah, so what I want to say here is just that you are aware that all of these in etiolizers are defined and all of these things are running. Okay? All right. Okay, so we've seen like a number of things and there's too much to get like, like what, which is the whole picture. So from all these, I've selected what I think I would like to have clear as a Rails parameter. Okay, so you've seen there's a lot of things going on. So this is the summary of the summaries, like, you know, the essential things that we need to know. All right. Summary of the summary. We go to the beginning of the presentation, okay, with boot, Airbnb and the kind of thing. So first, we define the load paths, which is bundle setup. So we have the gems, you know, the ones that we want to be available and not the ones we do not want to have available. Then we load the rail ties and this side effect defines all these configuration points of these in etiolizer, you know, active record and all the Rails components. After that, we load the gem dependencies with bundle require. Then the application class itself is evaluated. Okay, the definition of the application class itself is evaluate. And then there's a bunch of paths, like auto load paths, you know, load paths, stuff. All right. After that, and this is important, at this point, we load config environments, development Airbnb, production Airbnb, whatever. And this is why the configuration in these files takes precedence over the one in config application Airbnb, simply because it runs after it. Okay? So if you say foo equals one in application Airbnb, and since after that you run config environments, development Airbnb, for instance, and you say foo equals two, so it takes precedence just because it's, you know, evaluated, you know, later, and that's the one that remains. After that, the in etiolizer in the application engines or whatever are run. Okay? So first application, then development Airbnb, production Airbnb, whatever. After that, config in etiolizer. These ones are executed in lexicographic order, and after that, if needed, the application is eager loaded. That happens in production mode, by default. Well, another thing, so, yeah, parentheses. So we've seen that realties integrate into Rails via configuration points, all right? And in general, something curious as well is that in Rails, in general, in general, maybe if you do a rep, maybe you find a contract example, but in general, the Rails code base is not full of, if development question mark, if production question mark, no, no, no, the interface is, we have parametrized Rails using configuration points. Okay? And when you generate an application, development Airbnb, production Airbnb, whatever, sets, you know, sensible defaults for that environment. And then Rails just checks this configuration, all right? So it's not that in production, you do something. It's that in production, by, you know, the default generated in production has a value that makes that happen. Okay? Right? So we run these ones, eager load, we load the routes, and if we were running command, then the hooks of the command are run. Okay? So this is like the most important sequence of things that we have to remember, all right? And that's it. All right. Thank you. Thank you.
 We are going to see a talk about the Rails boot process and I would like to explain before  the goals of this talk.  So in this talk, we are going to see a few things related to this topic.  For instance, if you open the config directory, there are a number of files that we normally  never touch that are generated, like this config boot, convic environment, and so we  are going to see what they do.  And Rails components in general can work independently of Rails.  So Active Support, for instance, is a library that you know you can use in Ruby script,  you know, that is not running inside the Rails application.  Also for instance, you can use Active Record outside Rails.  You can have like a regular Ruby script using Active Record connecting to everything, you  know, you have everything.  But somehow, magically, you know, you launch a Rails application and all these independent  components are, you know, somehow organized for you and seamlessly you use them, you  know, and there is nothing that the programmer has to do to get these things working together.  And we are going to see how that works.  And you know, the final goal is to understand more or less what happens when.  Okay?  I say more or less because there is a lot happening, but we are going to have a good  sense of what happens when.  And for this talk, we are going to have to take into account a few things.  First, the approach of the talk is thought for Rails parameters, all right?  So for instance, it's not going to be like, you know, a walkthrough of, you know, of code  and code and code and see the rune path of these things.  So we are going to see code, but it's not a walkthrough.  So with this talk, I have tried to explain what I would like to know as a Rails parameter  about the root process, the boot process, okay?  And it is something that I would like an, an any guide to cover, you know, that kind  of information.  In the boot process, we have rail ties and we have engines, but this is not a talk about  rail ties and engines.  We are going to see what they are, but that's, that's a topic for, for the whole talk, okay?  So we are going to see only what is needed for this talk about rail ties and engines.  Therefore, we are going to see some code snippets, but they are going to be, like, heavily,  heavily edited.  So I, I have not tried, even tried that, that you want this, so that the, the slides makes  clear this has been edited, you know, with ellipse, with ellipses or something like that.  We put, like, a big warning and in general, the code we are going to see if you open the  real file is going to have more stuff, okay?  But there's a lot going on and I tried to select and, you know, uncut everything out  that was not relevant to the, to the topic we are talking about.  And finally, we are going to ignore spring, you know, so the boot process assuming that,  no, no, no, no.  This is the boot process, you know, the vanilla thing, okay, without, without additions.  All right.  So normally when, when you, when you think about booting rails, you, you have a server  in mind, okay?  You, you, you launch the application, you launch the server, you can, you are able to,  to serve requests and everything.  But there are more things that, that boot rails.  So for instance, if you run the console, you know that somehow you have everything in the  application available in the console, right?  Also runner, if you run, you know, if you pass runner a string or, or a filename, it  gets executed in the context of the application.  So somehow the application has been booted for, you know, in order to run these commands.  Runner indeed is a command that I love, I, I believe I run this command every day.  So it allows you to run something quickly instead of launching the console and then  control D and that kind of thing.  You just, you know, runner something and indeed to understand the rails, the, the, the rails  initialization, runner one, which is execute the program that has a literal one, you know,  it's something that I do often, you know.  So that's the minimum thing, the minimum thing, Rails runner one, the minimum thing  that, you know, loads what it has to load, does what it has to do and then there's no  more side effects except a blockchain one, which is not allowed.  And also in some great tasks, you know, that you have also the environment load.  So booting the application means being ready to serve all these kind of things.  All right, so let's open bin rails.  Okay.  This is a file that is generated, but in any, at least modern Rails application.  And we have here config boot, we load config boot and then it doesn't require something.  Okay.  If you open bin rake, you will see that it loads config boot and then does a stuff related  to rake.  Okay.  So these both, these both files start loading config boot.  That's the first thing.  And if you open config boot, you will see that is basically doing bundler setup.  Okay.  Bundler setup configures the load paths so the application is able to require the gems  that are in the gem file with, you know, with all the constraints and everything and is  not able to load gems that are outside that thing.  Okay.  So bundler setup tricks load path and I don't know, all is needed so that that is going  to work.  Then if you open config rule, which is what you execute when you launch a server, you  will see that it requires config environment.  Okay.  And then does something.  Config environment is another important, important file.  It loads application and this is config application RV, which is the first file we normally, you  know, working as a programmer, that's the kind of the first thing, you know, config  application RV is where stuff starts, where you can config, I don't know, time zone, that  kind of stuff.  Okay.  So that's the file that is being referenced here.  And then very important, it runs Rails application in italyse.  And this is the magic.  So in italyse, this method is the one that runs all the initializations.  Up to now, we are like setting things up, you know, to be able to do this.  And this is config application RV, which loads Rails all and then executes bundler require  with the groups that are relevant to that execution.  Okay.  So Rails all, we are not going to see, we are going to see Rails all later.  Okay.  Forget about it for a moment.  But the point here is that we are doing bundle require.  At this point is when the gem dependencies are loaded, okay, unless you opt out, okay,  at this point.  And after that, we evaluate the class that defines the application itself, which is,  you know, this thing that is named after, you know, what you pass to the new command,  that kind of thing.  Okay.  So the presentation is organized in a few blocks.  And we are going to be a bit like a roller coaster.  Okay.  So we are going to dive a little bit in something and then I'll leave it up, doing some summaries.  Okay.  So this is the summary of what we have seen up to this point.  So define load paths.  We have the gem dependencies ready.  Then load Rails all, which is something that is going to be seen later.  Then we actually load the dependencies, define application class, run initialize.  That's like the script, you know, that's the order in which things run in at this point.  And it's initialize that does, you know, the proper Rails boot process.  Okay.  All right.  Rails-RailTie.  So Rails-RailTie is a class that provides a number of things so that extensions and, you  know, are able to hook into this process.  For instance, it provides hooks to run code when you launch a console, when you launch  the runner command, you know.  So you can say as a gem, you can say, hey, if I am loaded in a Rails application and  the console is launched, please call this code.  Okay.  So we may have, you know, a series of blocks like this that are scheduled to run at that  point.  Then you have the ability to define custom configuration points.  Okay.  So when you see, like, for instance, config.activerecord.something, you know, a RailTie, we're  going to see later that ActiveRecord is a RailTie, allows you to define configuration  points so that applications are able to, you know, to express the configuration they want.  And also very important, they have the ability to declare code to be executed during boot.  So these are called initializers.  Okay.  So hooks, configuration points, and the ability to declare.  So Rails can declare that I want to run something when the inedulation happens, which is something  I don't know.  Okay.  RailTies are defined by suppressing this class, this very class.  And Rails knows which RailTies are defined because there's an inherited hook, you know,  that when Rails, RailTie is subclassed, there's an inherited hook that say, hey, I have been  subclassed and that by definition is a RailTie.  Okay.  Well, there's a technical thing about some special subclasses that I ignored, but that's  the idea.  So let's see an example.  Okay.  So this is, for instance, a RailTie or FactoryGal.  And this initializer thing with a block is, FactoryGal is declaring when the application  is initialized and I don't know when that is, you know, but when it happens, you've  got to run this code.  So for instance, FactoryGal at this point knows that Rails root is already defined.  Okay.  That's a contract.  You know you can assume that.  Okay.  And in this case, FactoryGal is setting up some factory paths or something like that.  Okay.  So the way FactoryGal, so FactoryGal needs to define some paths that depend on the Rails  application.  And the way to do that in an integrated way with Rails is to define a RailTie and say,  okay, when you are booting, call me and I will, I will configure myself.  All right.  So Rails components are integrated into the framework using RailTies.  For instance, this is the RailTie of ActiveRecord.  ActiveRecord defines a RailTie to integrate into the framework.  In this case, for instance, this is an example.  This is one of, this is the hook that tells Rails to run this code if the console is launched.  Okay.  So if the console is launched, if it's launched in sandbox mode, which is a mode that starts  a transaction and rollbacks a transaction when the console, when the session is over,  okay, load some code, I have not copied here, okay, load whatever you need to support this  thing.  And for instance, then you have, you know, that recently in the console, you get, you  get the SQL logins in, you know, there.  So there's code that says, okay, unlock to standard error.  All right.  So that's the way ActiveRecord integrates into Rails by defining a RailTie that does  this and does a lot of other things, all right?  Okay.  For instance, this is from ActionDispatch.  And we are seeing here an example of configuration.  We saw before an example of hooking into the console.  Now we see an example with configuration.  So for instance, this is the way ActionDispatch defines a configuration point called tld underscore  length and it gives this configuration point a default, which is one, okay?  This is from ActiveSupport.  And this is another Initializer.  We saw an Initializer for FactoryGal.  We are now seeing an Initializer for ActiveSupport.  And we do not need to understand this code, but it's basically taking the time zone that  the application has configured and setting whatever ActiveSupport needs to set up to  take into account that configuration point.  Okay.  So that's what Rails all does.  Rails all is just, you know, it just loads all the Rails ties of the different components  in Rails.  So application.rb loads this file.  This file is just looping and loads everything, all right?  And as a side effect of loading these things, we have first that Rails knows that RailTie  has been suplaced.  So we are able to list the RailTies that have been loaded.  And also as a side effect of loading these, we have the configuration points, the declarations  of the Initializer.  So it's like a setup, okay?  And that's the way the components work seamlessly in a Rails application.  So the application, in reality, well, as a rule of thumb, let's say, maybe it's not  100% in all cases, but as a rule of thumb, this is, I don't know, I like to remind this  design.  So Rails is not coupled to the components.  Rails is kind of agnostic to most of them, all right?  So Rails does not have in the Initialization process anything that hardcodes the stuff  to integrate the components.  It goes the other way around.  So the RailTies are loaded, and the configuration points are the interface between Rails and  these components, okay?  So ActiveRecord just loads and say, hey, call me the console, please run this Initializer,  blah, blah, blah, blah, blah, okay?  And the same for the rest of Rails components.  And the RailTies, so are the components that know that they are living in a pattern application,  okay?  That's the way they integrate.  So Rails does not hardcode in general anything about ActiveRecord, that kind of thing.  Rails just exposes a number of configuration points, ActiveRecord loads, takes the configuration  points that it needs to set up itself, and you know, you are set, okay?  That's the idea.  So Avonilla Rails application has 15 RailTies, which are these ones, okay?  So you see, everyone that needs to integrate with all these processes has to define a RailTie.  All right.  Next block, lazy loading.  So in general, so example of heavily edited code, this is ActiveRecord, which has a lot  of things, okay?  All right.  So in general, if you open like the root file of the Rails components, you will see a lot  of autoloads like this one, okay?  This is the autoload of Ruby.  Yeah, so Rails redefines because autoload in Ruby needs, you know, the constant and then  it needs a path, all right?  But when you follow naming conventions for the files and you write this thing three times,  so the reaction is to write something that automates this using the convention.  So modules that, this is the Ruby autoload, not the Rails autoload of constants, okay?  So in general, when you boot, Rails tries to be as lazy as possible loading things,  so you have the, you know, the minimal things to do when you boot.  One of them is setting autoloads for, you know, this is the ActiveRecord, is the name  space, so ActiveRecord base, ActiveRecord, I don't know, whatever, is going to be autoload.  So it's not going to be ActiveRecord base, it's not going to be required on boot.  It's going to be required when it's needed, you know?  And that's thanks to autoload.  So since things are going to be loaded only when needed, and there's code that needs to  know, hey, have you loaded already ActiveRecord, for instance, to include something, Net of  Record Base or whatever, there's this utility which is ActiveSupport on load.  So for instance, in the ActiveRecord Rayty, we have to set up the logger of ActiveRecord.  And the Initializer does not go straight away, you know, assigning the logger.  Because the way to do this orderly is you declare that when ActiveRecord is loaded,  then please set the logger with, you know, the block that I am passing here.  Okay?  So that's the way, you know, to defer as much as possible things in order to have as a boot  process as lightweight as possible.  And at the end of ActiveRecord base, at the end of ActiveRecord base, which is what ActiveRecord  considers to be, you know, loading ActiveRecord, you know, by definition is evaluating this  file, it says, room load hooks for ActiveRecord.  Okay?  So when this file is evaluated, all the, you know, the class is defined.  And at the bottom of the file, you have this line.  And then everything that was, you know, scheduled to be run when ActiveRecord loads is going  to be, is going to be run at this point.  Okay.  Next block is Rails Engine.  Rails Engine is a subclass of, of Rails ties.  Okay?  Of Rails Rails.  They are defined as well.  So Rails were defined by subclassing Rails Rails and engines are defined by subclassing  Rails Engine.  So it's the same, the same kind of thing.  Okay?  And what is an engine?  So this, this would be like one, two, three talks.  But just, you know, so just to get the idea of what it is, first it heritage everything  from Rails, Rails.  So always, always, we, we saw before about console, runner, you know, hooks, initializers,  config points, that's all available here.  But it's like a super set.  You can do more things with an engine.  So for instance, you can, you know, you, you can define controllers, models, that kind  of thing.  You have initializers as well, assets, you know, a bunch of things.  So it's, it's closer to like, you know, unless you are able to define like a subset of an  application, that's the idea for an engine.  Okay?  So engines have predefined some configuration points and also some initializers.  All right?  So just by subclassing engine, you got some configuration and some initializers for starters.  So this is the one that are inherited.  So when you define an engine subclassing Rails engine, you get this kind of thing.  So you're going to set the load path of the engine.  Okay?  So adding your own lead directory or whatever, you know, to APP models, whatever, to the load  path that is already set.  Auto load path, routing paths, locale, a number of things.  Okay?  So it is not important to, to follow every single step of this, you know, it's maybe  too detailed, but just, you know, to give an idea of the kind of things that, that you  inherit from an engine.  View paths, load environment config is the, these are initializers.  This is the initializer that runs whatever you have in config environments, develop config  environments, productionary, whatever.  And then some other paths.  Then you load config initializers, all right, disorder.  And then there's a technical hook engines black point that says you've, at this point,  you have already run a number of things.  If you are interested in hooking into this, you can, all right?  So initializers by default go like in chain, but you can say this has to run before this  or the initializer or this has to run after that one.  And there are a number of technical points in order to, to be able to do that.  And a vanilla rage application, which is like rage new, you know, what, what, what do we  get with rage new?  There are four engines.  So this, this four, okay?  Okay.  Action cable is an engine.  It has an engine.  So the rest of rage components have rail ties because with a rail tie is, is enough.  What they have to do on boot.  And actual cables has some assets.  And that's the, that's the reason it, it is an engine.  All right.  And we, we are arriving to rage application, which is a subclass of engines.  So look at this hierarchy.  So the base thing is a rail tie.  Then we have an engine and an application is a subclass of engines.  So you know, the application is like a particular case of all this design.  Okay.  Beautiful.  I think it's beautiful.  All right.  So they are defined by subclassing.  And that, that's what you do in config application or B. If you remember, you have your application  subclassing, race application.  That's exactly what that file is doing.  So the application is a, indeed is a singleton.  You know, there's one, there's just one instance of that class and you can access that instance  using race dot application, which is a method.  And when the singleton is instantiate, you, you get a hook, call it before configuration.  That's also just something that is fired.  And if you're in a, in a rail tie, for instance, you say config dot before configuration, execute  something is going to be executed at this point, which is just when the application is  just, you know, you instantly, it got instantiate, you get this code called.  Okay.  So application execute for groups of initializers, for groups.  It's organized this way.  First you have the ones inherited from race engine.  Okay.  Race engine have some pre-configured ones.  So those ones you inherit, therefore they are going to be executed.  Then there's a bootstrap group that does like super basic things like setting up paths and  that kind of thing.  And we have the initializers of all the rail ties and engines that the application has  load.  Okay.  And the way this is load is because we have a bundle require in config application.  So if you have an extension, a gem or something implementing a rail tie or an engine, so what  happens is that when bundle require loads that gem, that gem, you know, at that point  defines the rail tie or the engine so that is, you know, so that the application knows  about the existence of this thing.  And then there's a finishes group that does, you know, some training stuff.  So the bootstrap group, for instance, the first one is a technical hook as well.  Then for instance, we load active support.  So active support, that's not something optional.  All, you know, the whole rails uses active support.  Okay.  So straight away, you, this one is hard code.  This one is loaded.  Okay.  Yeah.  So this loads active support all, which brings you everything in active support unless there's  a configuration point which is config active support bear, which says instead of loading  everything, just load whatever the application, I mean, whatever rails needs, you know, to  run.  And this light means that we are finishing.  No?  All right.  I saw a change.  Okay.  Okay.  Fine.  Yeah.  So you are able to load, you know, the minimum of active support.  Okay.  And that said, I have never seen this one used.  So, but we have it there.  Then eager load, you initialize the logger.  This is the bootstrap log, the bootstrap group.  Okay.  So you initialize the logger, the cache, the way constant auto loading loads things which  can be load or require depending on the environment or configuration.  And then there's a before initialize hook, details, too much details.  Okay.  There are a number of things that are going on just having a look.  And then rail ties and engines in a vanilla rails application have 94 initializers declared.  Okay.  It's too much.  So then we have the finisher group.  Okay.  So things more or less, you can think that they run more or less in order except that  the before and after things that are, you know, when you declare a relation, you can  say before this and after this, you know, unless you have defined something, you can  more or less think that they go in order.  Okay.  So yeah, a number of things.  The finisher group does a number of things.  Configure, sleep templates in case generators need to load things from here.  Yeah, this second one is technical.  Then this one is defining, you know, you know that if you go in development mode to rails  info, you get some pages there.  And if you go to the home, you get this new shiny thing, you know, in Rails 5.  So the way that works, if you go to config routes, that's not in config routes, so how  is that served?  All right.  So the routes are defined here.  Those ones are defined here.  You build the middleware stack at this point.  So we are kind of already late.  Okay.  You have to think we are already, most of the things are done at this point.  Well, you define main app, which is something for engines.  Doesn't matter.  To prepare blocks, important is a block that are run, you know, in certain, certain, you  know, certain points of the run time.  And eager load is important.  By default in production, you eager load the application.  And then there's another technical hook, which is the finisher hook that fires another,  you know, another event, which is after initializing case you have to do something after this  has run.  All right.  And a number of things that are too detailed maybe.  Well, the second one loads the routes.  This one is important.  Okay.  But there are a number of things in this finisher group going on.  Okay.  So once everything has been declared and we have everything load, you know, there's a  topological sort going on here.  So an etiolizer have an after, before topological sort, if someone does not know.  Similarly if you have things that have an order, a relative order declared, like I have  to run at some point, but make sure it's before that thing.  Or I have to run at some point, but make sure it's after that other thing.  Okay.  So a topological sort is getting this linear in a way that respects these relative constraints.  Okay.  So if you said you need to run before that thing, you are guaranteed that you are going  to run before that thing.  Okay.  Maybe not immediately before.  It doesn't matter.  So the constraint is relative.  Okay.  So maybe not just before, maybe two before.  I don't know.  It depends on the other things that have said that need to be run before that hook.  Okay.  So that's the idea in any case, we ordered the etiolizers to be run the way they have  declared to be run.  So at this shag one, we have 124 etiolizers.  There's a lot going on.  Okay.  Because everything, you know, this is designed so that everything that needs to happen at  boot is going to be generally happening in an etiolizer.  So there's a lot of things, 124.  And I have listed all of them.  So if you get then a PDF or we see the video, we have them at least, you know, as a reference.  This is not like public interface.  This is not something Rails is telling you these are going to exist.  You can, you know, you can assume that all of these 124 are going to exist in other releases  or things like that.  But anyway, just for the sake of the presentation, these are the ones I am just going to pass  the slides because, you know, there's no point in going one by one.  But you know, you see, we have setting load paths here, then out to load paths, you know,  and there are like, all right.  So yeah, so what I want to say here is just that you are aware that all of these in etiolizers  are defined and all of these things are running.  Okay?  All right.  Okay, so we've seen like a number of things and there's too much to get like, like what,  which is the whole picture.  So from all these, I've selected what I think I would like to have clear as a Rails parameter.  Okay, so you've seen there's a lot of things going on.  So this is the summary of the summaries, like, you know, the essential things that we need  to know.  All right.  Summary of the summary.  We go to the beginning of the presentation, okay, with boot, Airbnb and the kind of thing.  So first, we define the load paths, which is bundle setup.  So we have the gems, you know, the ones that we want to be available and not the ones we  do not want to have available.  Then we load the rail ties and this side effect defines all these configuration points of  these in etiolizer, you know, active record and all the Rails components.  After that, we load the gem dependencies with bundle require.  Then the application class itself is evaluated.  Okay, the definition of the application class itself is evaluate.  And then there's a bunch of paths, like auto load paths, you know, load paths, stuff.  All right.  After that, and this is important, at this point, we load config environments, development  Airbnb, production Airbnb, whatever.  And this is why the configuration in these files takes precedence over the one in config  application Airbnb, simply because it runs after it.  Okay?  So if you say foo equals one in application Airbnb, and since after that you run config  environments, development Airbnb, for instance, and you say foo equals two, so it takes precedence  just because it's, you know, evaluated, you know, later, and that's the one that remains.  After that, the in etiolizer in the application engines or whatever are run.  Okay?  So first application, then development Airbnb, production Airbnb, whatever.  After that, config in etiolizer.  These ones are executed in lexicographic order, and after that, if needed, the application  is eager loaded.  That happens in production mode, by default.  Well, another thing, so, yeah, parentheses.  So we've seen that realties integrate into Rails via configuration points, all right?  And in general, something curious as well is that in Rails, in general, in general, maybe  if you do a rep, maybe you find a contract example, but in general, the Rails code base  is not full of, if development question mark, if production question mark, no, no, no, the  interface is, we have parametrized Rails using configuration points.  Okay?  And when you generate an application, development Airbnb, production Airbnb, whatever, sets,  you know, sensible defaults for that environment.  And then Rails just checks this configuration, all right?  So it's not that in production, you do something.  It's that in production, by, you know, the default generated in production has a value  that makes that happen.  Okay?  Right?  So we run these ones, eager load, we load the routes, and if we were running command,  then the hooks of the command are run.  Okay?  So this is like the most important sequence of things that we have to remember, all right?  And that's it.  All right.  Thank you.  Thank you.
The_Rails_Boot_Process_0_47.png The_Rails_Boot_Process_48_119.png The_Rails_Boot_Process_120_239.png The_Rails_Boot_Process_240_311.png The_Rails_Boot_Process_312_575.png The_Rails_Boot_Process_576_3011.png The_Rails_Boot_Process_3012_6131.png The_Rails_Boot_Process_6132_6551.png The_Rails_Boot_Process_6552_8603.png The_Rails_Boot_Process_8604_9203.png The_Rails_Boot_Process_9204_9443.png The_Rails_Boot_Process_9444_12059.png The_Rails_Boot_Process_12060_13535.png The_Rails_Boot_Process_13536_15035.png The_Rails_Boot_Process_15036_15131.png The_Rails_Boot_Process_15132_17795.png The_Rails_Boot_Process_17796_20051.png The_Rails_Boot_Process_20052_22403.png The_Rails_Boot_Process_22404_24455.png The_Rails_Boot_Process_24456_27131.png The_Rails_Boot_Process_27132_27599.png The_Rails_Boot_Process_27600_31367.png The_Rails_Boot_Process_31368_32375.png The_Rails_Boot_Process_32376_32519.png The_Rails_Boot_Process_32520_32747.png The_Rails_Boot_Process_32748_34619.png The_Rails_Boot_Process_34620_36095.png The_Rails_Boot_Process_36096_37211.png The_Rails_Boot_Process_37212_38723.png The_Rails_Boot_Process_38724_39911.png The_Rails_Boot_Process_39912_41735.png The_Rails_Boot_Process_41736_43739.png The_Rails_Boot_Process_43740_44459.png The_Rails_Boot_Process_44460_44795.png The_Rails_Boot_Process_44796_47615.png The_Rails_Boot_Process_47616_49955.png The_Rails_Boot_Process_49956_50615.png The_Rails_Boot_Process_50616_51683.png The_Rails_Boot_Process_51684_51779.png The_Rails_Boot_Process_51780_51851.png The_Rails_Boot_Process_51852_52319.png The_Rails_Boot_Process_52320_52427.png The_Rails_Boot_Process_52428_53291.png The_Rails_Boot_Process_53292_54839.png The_Rails_Boot_Process_54840_58679.png The_Rails_Boot_Process_58680_58907.png The_Rails_Boot_Process_58908_59027.png The_Rails_Boot_Process_59028_59171.png The_Rails_Boot_Process_59172_59175.png
We are going to see a talk about the Rails boot process and I would like to explain before the goals of this talk. So in this talk, we are going to see a few things related to this topic. For instance, if you open the config directory, there are a number of files that we normally never touch that are generated, like this config boot, convic environment, and so we are going to see what they do. And Rails components in general can work independently of Rails. So Active Support, for instance, is a library that you know you can use in Ruby script, you know, that is not running inside the Rails application. Also for instance, you can use Active Record outside Rails. You can have like a regular Ruby script using Active Record connecting to everything, you know, you have everything. But somehow, magically, you know, you launch a Rails application and all these independent components are, you know, somehow organized for you and seamlessly you use them, you know, and there is nothing that the programmer has to do to get these things working together. And we are going to see how that works. And you know, the final goal is to understand more or less what happens when. Okay? I say more or less because there is a lot happening, but we are going to have a good sense of what happens when. And for this talk, we are going to have to take into account a few things. First, the approach of the talk is thought for Rails parameters, all right? So for instance, it's not going to be like, you know, a walkthrough of, you know, of code and code and code and see the rune path of these things. So we are going to see code, but it's not a walkthrough. So with this talk, I have tried to explain what I would like to know as a Rails parameter about the root process, the boot process, okay? And it is something that I would like an, an any guide to cover, you know, that kind of information. In the boot process, we have rail ties and we have engines, but this is not a talk about rail ties and engines. We are going to see what they are, but that's, that's a topic for, for the whole talk, okay? So we are going to see only what is needed for this talk about rail ties and engines. Therefore, we are going to see some code snippets, but they are going to be, like, heavily, heavily edited. So I, I have not tried, even tried that, that you want this, so that the, the slides makes clear this has been edited, you know, with ellipse, with ellipses or something like that. We put, like, a big warning and in general, the code we are going to see if you open the real file is going to have more stuff, okay? But there's a lot going on and I tried to select and, you know, uncut everything out that was not relevant to the, to the topic we are talking about. And finally, we are going to ignore spring, you know, so the boot process assuming that, no, no, no, no. This is the boot process, you know, the vanilla thing, okay, without, without additions. All right. So normally when, when you, when you think about booting rails, you, you have a server in mind, okay? You, you, you launch the application, you launch the server, you can, you are able to, to serve requests and everything. But there are more things that, that boot rails. So for instance, if you run the console, you know that somehow you have everything in the application available in the console, right? Also runner, if you run, you know, if you pass runner a string or, or a filename, it gets executed in the context of the application. So somehow the application has been booted for, you know, in order to run these commands. Runner indeed is a command that I love, I, I believe I run this command every day. So it allows you to run something quickly instead of launching the console and then control D and that kind of thing. You just, you know, runner something and indeed to understand the rails, the, the, the rails initialization, runner one, which is execute the program that has a literal one, you know, it's something that I do often, you know. So that's the minimum thing, the minimum thing, Rails runner one, the minimum thing that, you know, loads what it has to load, does what it has to do and then there's no more side effects except a blockchain one, which is not allowed. And also in some great tasks, you know, that you have also the environment load. So booting the application means being ready to serve all these kind of things. All right, so let's open bin rails. Okay. This is a file that is generated, but in any, at least modern Rails application. And we have here config boot, we load config boot and then it doesn't require something. Okay. If you open bin rake, you will see that it loads config boot and then does a stuff related to rake. Okay. So these both, these both files start loading config boot. That's the first thing. And if you open config boot, you will see that is basically doing bundler setup. Okay. Bundler setup configures the load paths so the application is able to require the gems that are in the gem file with, you know, with all the constraints and everything and is not able to load gems that are outside that thing. Okay. So bundler setup tricks load path and I don't know, all is needed so that that is going to work. Then if you open config rule, which is what you execute when you launch a server, you will see that it requires config environment. Okay. And then does something. Config environment is another important, important file. It loads application and this is config application RV, which is the first file we normally, you know, working as a programmer, that's the kind of the first thing, you know, config application RV is where stuff starts, where you can config, I don't know, time zone, that kind of stuff. Okay. So that's the file that is being referenced here. And then very important, it runs Rails application in italyse. And this is the magic. So in italyse, this method is the one that runs all the initializations. Up to now, we are like setting things up, you know, to be able to do this. And this is config application RV, which loads Rails all and then executes bundler require with the groups that are relevant to that execution. Okay. So Rails all, we are not going to see, we are going to see Rails all later. Okay. Forget about it for a moment. But the point here is that we are doing bundle require. At this point is when the gem dependencies are loaded, okay, unless you opt out, okay, at this point. And after that, we evaluate the class that defines the application itself, which is, you know, this thing that is named after, you know, what you pass to the new command, that kind of thing. Okay. So the presentation is organized in a few blocks. And we are going to be a bit like a roller coaster. Okay. So we are going to dive a little bit in something and then I'll leave it up, doing some summaries. Okay. So this is the summary of what we have seen up to this point. So define load paths. We have the gem dependencies ready. Then load Rails all, which is something that is going to be seen later. Then we actually load the dependencies, define application class, run initialize. That's like the script, you know, that's the order in which things run in at this point. And it's initialize that does, you know, the proper Rails boot process. Okay. All right. Rails-RailTie. So Rails-RailTie is a class that provides a number of things so that extensions and, you know, are able to hook into this process. For instance, it provides hooks to run code when you launch a console, when you launch the runner command, you know. So you can say as a gem, you can say, hey, if I am loaded in a Rails application and the console is launched, please call this code. Okay. So we may have, you know, a series of blocks like this that are scheduled to run at that point. Then you have the ability to define custom configuration points. Okay. So when you see, like, for instance, config.activerecord.something, you know, a RailTie, we're going to see later that ActiveRecord is a RailTie, allows you to define configuration points so that applications are able to, you know, to express the configuration they want. And also very important, they have the ability to declare code to be executed during boot. So these are called initializers. Okay. So hooks, configuration points, and the ability to declare. So Rails can declare that I want to run something when the inedulation happens, which is something I don't know. Okay. RailTies are defined by suppressing this class, this very class. And Rails knows which RailTies are defined because there's an inherited hook, you know, that when Rails, RailTie is subclassed, there's an inherited hook that say, hey, I have been subclassed and that by definition is a RailTie. Okay. Well, there's a technical thing about some special subclasses that I ignored, but that's the idea. So let's see an example. Okay. So this is, for instance, a RailTie or FactoryGal. And this initializer thing with a block is, FactoryGal is declaring when the application is initialized and I don't know when that is, you know, but when it happens, you've got to run this code. So for instance, FactoryGal at this point knows that Rails root is already defined. Okay. That's a contract. You know you can assume that. Okay. And in this case, FactoryGal is setting up some factory paths or something like that. Okay. So the way FactoryGal, so FactoryGal needs to define some paths that depend on the Rails application. And the way to do that in an integrated way with Rails is to define a RailTie and say, okay, when you are booting, call me and I will, I will configure myself. All right. So Rails components are integrated into the framework using RailTies. For instance, this is the RailTie of ActiveRecord. ActiveRecord defines a RailTie to integrate into the framework. In this case, for instance, this is an example. This is one of, this is the hook that tells Rails to run this code if the console is launched. Okay. So if the console is launched, if it's launched in sandbox mode, which is a mode that starts a transaction and rollbacks a transaction when the console, when the session is over, okay, load some code, I have not copied here, okay, load whatever you need to support this thing. And for instance, then you have, you know, that recently in the console, you get, you get the SQL logins in, you know, there. So there's code that says, okay, unlock to standard error. All right. So that's the way ActiveRecord integrates into Rails by defining a RailTie that does this and does a lot of other things, all right? Okay. For instance, this is from ActionDispatch. And we are seeing here an example of configuration. We saw before an example of hooking into the console. Now we see an example with configuration. So for instance, this is the way ActionDispatch defines a configuration point called tld underscore length and it gives this configuration point a default, which is one, okay? This is from ActiveSupport. And this is another Initializer. We saw an Initializer for FactoryGal. We are now seeing an Initializer for ActiveSupport. And we do not need to understand this code, but it's basically taking the time zone that the application has configured and setting whatever ActiveSupport needs to set up to take into account that configuration point. Okay. So that's what Rails all does. Rails all is just, you know, it just loads all the Rails ties of the different components in Rails. So application.rb loads this file. This file is just looping and loads everything, all right? And as a side effect of loading these things, we have first that Rails knows that RailTie has been suplaced. So we are able to list the RailTies that have been loaded. And also as a side effect of loading these, we have the configuration points, the declarations of the Initializer. So it's like a setup, okay? And that's the way the components work seamlessly in a Rails application. So the application, in reality, well, as a rule of thumb, let's say, maybe it's not 100% in all cases, but as a rule of thumb, this is, I don't know, I like to remind this design. So Rails is not coupled to the components. Rails is kind of agnostic to most of them, all right? So Rails does not have in the Initialization process anything that hardcodes the stuff to integrate the components. It goes the other way around. So the RailTies are loaded, and the configuration points are the interface between Rails and these components, okay? So ActiveRecord just loads and say, hey, call me the console, please run this Initializer, blah, blah, blah, blah, blah, okay? And the same for the rest of Rails components. And the RailTies, so are the components that know that they are living in a pattern application, okay? That's the way they integrate. So Rails does not hardcode in general anything about ActiveRecord, that kind of thing. Rails just exposes a number of configuration points, ActiveRecord loads, takes the configuration points that it needs to set up itself, and you know, you are set, okay? That's the idea. So Avonilla Rails application has 15 RailTies, which are these ones, okay? So you see, everyone that needs to integrate with all these processes has to define a RailTie. All right. Next block, lazy loading. So in general, so example of heavily edited code, this is ActiveRecord, which has a lot of things, okay? All right. So in general, if you open like the root file of the Rails components, you will see a lot of autoloads like this one, okay? This is the autoload of Ruby. Yeah, so Rails redefines because autoload in Ruby needs, you know, the constant and then it needs a path, all right? But when you follow naming conventions for the files and you write this thing three times, so the reaction is to write something that automates this using the convention. So modules that, this is the Ruby autoload, not the Rails autoload of constants, okay? So in general, when you boot, Rails tries to be as lazy as possible loading things, so you have the, you know, the minimal things to do when you boot. One of them is setting autoloads for, you know, this is the ActiveRecord, is the name space, so ActiveRecord base, ActiveRecord, I don't know, whatever, is going to be autoload. So it's not going to be ActiveRecord base, it's not going to be required on boot. It's going to be required when it's needed, you know? And that's thanks to autoload. So since things are going to be loaded only when needed, and there's code that needs to know, hey, have you loaded already ActiveRecord, for instance, to include something, Net of Record Base or whatever, there's this utility which is ActiveSupport on load. So for instance, in the ActiveRecord Rayty, we have to set up the logger of ActiveRecord. And the Initializer does not go straight away, you know, assigning the logger. Because the way to do this orderly is you declare that when ActiveRecord is loaded, then please set the logger with, you know, the block that I am passing here. Okay? So that's the way, you know, to defer as much as possible things in order to have as a boot process as lightweight as possible. And at the end of ActiveRecord base, at the end of ActiveRecord base, which is what ActiveRecord considers to be, you know, loading ActiveRecord, you know, by definition is evaluating this file, it says, room load hooks for ActiveRecord. Okay? So when this file is evaluated, all the, you know, the class is defined. And at the bottom of the file, you have this line. And then everything that was, you know, scheduled to be run when ActiveRecord loads is going to be, is going to be run at this point. Okay. Next block is Rails Engine. Rails Engine is a subclass of, of Rails ties. Okay? Of Rails Rails. They are defined as well. So Rails were defined by subclassing Rails Rails and engines are defined by subclassing Rails Engine. So it's the same, the same kind of thing. Okay? And what is an engine? So this, this would be like one, two, three talks. But just, you know, so just to get the idea of what it is, first it heritage everything from Rails, Rails. So always, always, we, we saw before about console, runner, you know, hooks, initializers, config points, that's all available here. But it's like a super set. You can do more things with an engine. So for instance, you can, you know, you, you can define controllers, models, that kind of thing. You have initializers as well, assets, you know, a bunch of things. So it's, it's closer to like, you know, unless you are able to define like a subset of an application, that's the idea for an engine. Okay? So engines have predefined some configuration points and also some initializers. All right? So just by subclassing engine, you got some configuration and some initializers for starters. So this is the one that are inherited. So when you define an engine subclassing Rails engine, you get this kind of thing. So you're going to set the load path of the engine. Okay? So adding your own lead directory or whatever, you know, to APP models, whatever, to the load path that is already set. Auto load path, routing paths, locale, a number of things. Okay? So it is not important to, to follow every single step of this, you know, it's maybe too detailed, but just, you know, to give an idea of the kind of things that, that you inherit from an engine. View paths, load environment config is the, these are initializers. This is the initializer that runs whatever you have in config environments, develop config environments, productionary, whatever. And then some other paths. Then you load config initializers, all right, disorder. And then there's a technical hook engines black point that says you've, at this point, you have already run a number of things. If you are interested in hooking into this, you can, all right? So initializers by default go like in chain, but you can say this has to run before this or the initializer or this has to run after that one. And there are a number of technical points in order to, to be able to do that. And a vanilla rage application, which is like rage new, you know, what, what, what do we get with rage new? There are four engines. So this, this four, okay? Okay. Action cable is an engine. It has an engine. So the rest of rage components have rail ties because with a rail tie is, is enough. What they have to do on boot. And actual cables has some assets. And that's the, that's the reason it, it is an engine. All right. And we, we are arriving to rage application, which is a subclass of engines. So look at this hierarchy. So the base thing is a rail tie. Then we have an engine and an application is a subclass of engines. So you know, the application is like a particular case of all this design. Okay. Beautiful. I think it's beautiful. All right. So they are defined by subclassing. And that, that's what you do in config application or B. If you remember, you have your application subclassing, race application. That's exactly what that file is doing. So the application is a, indeed is a singleton. You know, there's one, there's just one instance of that class and you can access that instance using race dot application, which is a method. And when the singleton is instantiate, you, you get a hook, call it before configuration. That's also just something that is fired. And if you're in a, in a rail tie, for instance, you say config dot before configuration, execute something is going to be executed at this point, which is just when the application is just, you know, you instantly, it got instantiate, you get this code called. Okay. So application execute for groups of initializers, for groups. It's organized this way. First you have the ones inherited from race engine. Okay. Race engine have some pre-configured ones. So those ones you inherit, therefore they are going to be executed. Then there's a bootstrap group that does like super basic things like setting up paths and that kind of thing. And we have the initializers of all the rail ties and engines that the application has load. Okay. And the way this is load is because we have a bundle require in config application. So if you have an extension, a gem or something implementing a rail tie or an engine, so what happens is that when bundle require loads that gem, that gem, you know, at that point defines the rail tie or the engine so that is, you know, so that the application knows about the existence of this thing. And then there's a finishes group that does, you know, some training stuff. So the bootstrap group, for instance, the first one is a technical hook as well. Then for instance, we load active support. So active support, that's not something optional. All, you know, the whole rails uses active support. Okay. So straight away, you, this one is hard code. This one is loaded. Okay. Yeah. So this loads active support all, which brings you everything in active support unless there's a configuration point which is config active support bear, which says instead of loading everything, just load whatever the application, I mean, whatever rails needs, you know, to run. And this light means that we are finishing. No? All right. I saw a change. Okay. Okay. Fine. Yeah. So you are able to load, you know, the minimum of active support. Okay. And that said, I have never seen this one used. So, but we have it there. Then eager load, you initialize the logger. This is the bootstrap log, the bootstrap group. Okay. So you initialize the logger, the cache, the way constant auto loading loads things which can be load or require depending on the environment or configuration. And then there's a before initialize hook, details, too much details. Okay. There are a number of things that are going on just having a look. And then rail ties and engines in a vanilla rails application have 94 initializers declared. Okay. It's too much. So then we have the finisher group. Okay. So things more or less, you can think that they run more or less in order except that the before and after things that are, you know, when you declare a relation, you can say before this and after this, you know, unless you have defined something, you can more or less think that they go in order. Okay. So yeah, a number of things. The finisher group does a number of things. Configure, sleep templates in case generators need to load things from here. Yeah, this second one is technical. Then this one is defining, you know, you know that if you go in development mode to rails info, you get some pages there. And if you go to the home, you get this new shiny thing, you know, in Rails 5. So the way that works, if you go to config routes, that's not in config routes, so how is that served? All right. So the routes are defined here. Those ones are defined here. You build the middleware stack at this point. So we are kind of already late. Okay. You have to think we are already, most of the things are done at this point. Well, you define main app, which is something for engines. Doesn't matter. To prepare blocks, important is a block that are run, you know, in certain, certain, you know, certain points of the run time. And eager load is important. By default in production, you eager load the application. And then there's another technical hook, which is the finisher hook that fires another, you know, another event, which is after initializing case you have to do something after this has run. All right. And a number of things that are too detailed maybe. Well, the second one loads the routes. This one is important. Okay. But there are a number of things in this finisher group going on. Okay. So once everything has been declared and we have everything load, you know, there's a topological sort going on here. So an etiolizer have an after, before topological sort, if someone does not know. Similarly if you have things that have an order, a relative order declared, like I have to run at some point, but make sure it's before that thing. Or I have to run at some point, but make sure it's after that other thing. Okay. So a topological sort is getting this linear in a way that respects these relative constraints. Okay. So if you said you need to run before that thing, you are guaranteed that you are going to run before that thing. Okay. Maybe not immediately before. It doesn't matter. So the constraint is relative. Okay. So maybe not just before, maybe two before. I don't know. It depends on the other things that have said that need to be run before that hook. Okay. So that's the idea in any case, we ordered the etiolizers to be run the way they have declared to be run. So at this shag one, we have 124 etiolizers. There's a lot going on. Okay. Because everything, you know, this is designed so that everything that needs to happen at boot is going to be generally happening in an etiolizer. So there's a lot of things, 124. And I have listed all of them. So if you get then a PDF or we see the video, we have them at least, you know, as a reference. This is not like public interface. This is not something Rails is telling you these are going to exist. You can, you know, you can assume that all of these 124 are going to exist in other releases or things like that. But anyway, just for the sake of the presentation, these are the ones I am just going to pass the slides because, you know, there's no point in going one by one. But you know, you see, we have setting load paths here, then out to load paths, you know, and there are like, all right. So yeah, so what I want to say here is just that you are aware that all of these in etiolizers are defined and all of these things are running. Okay? All right. Okay, so we've seen like a number of things and there's too much to get like, like what, which is the whole picture. So from all these, I've selected what I think I would like to have clear as a Rails parameter. Okay, so you've seen there's a lot of things going on. So this is the summary of the summaries, like, you know, the essential things that we need to know. All right. Summary of the summary. We go to the beginning of the presentation, okay, with boot, Airbnb and the kind of thing. So first, we define the load paths, which is bundle setup. So we have the gems, you know, the ones that we want to be available and not the ones we do not want to have available. Then we load the rail ties and this side effect defines all these configuration points of these in etiolizer, you know, active record and all the Rails components. After that, we load the gem dependencies with bundle require. Then the application class itself is evaluated. Okay, the definition of the application class itself is evaluate. And then there's a bunch of paths, like auto load paths, you know, load paths, stuff. All right. After that, and this is important, at this point, we load config environments, development Airbnb, production Airbnb, whatever. And this is why the configuration in these files takes precedence over the one in config application Airbnb, simply because it runs after it. Okay? So if you say foo equals one in application Airbnb, and since after that you run config environments, development Airbnb, for instance, and you say foo equals two, so it takes precedence just because it's, you know, evaluated, you know, later, and that's the one that remains. After that, the in etiolizer in the application engines or whatever are run. Okay? So first application, then development Airbnb, production Airbnb, whatever. After that, config in etiolizer. These ones are executed in lexicographic order, and after that, if needed, the application is eager loaded. That happens in production mode, by default. Well, another thing, so, yeah, parentheses. So we've seen that realties integrate into Rails via configuration points, all right? And in general, something curious as well is that in Rails, in general, in general, maybe if you do a rep, maybe you find a contract example, but in general, the Rails code base is not full of, if development question mark, if production question mark, no, no, no, the interface is, we have parametrized Rails using configuration points. Okay? And when you generate an application, development Airbnb, production Airbnb, whatever, sets, you know, sensible defaults for that environment. And then Rails just checks this configuration, all right? So it's not that in production, you do something. It's that in production, by, you know, the default generated in production has a value that makes that happen. Okay? Right? So we run these ones, eager load, we load the routes, and if we were running command, then the hooks of the command are run. Okay? So this is like the most important sequence of things that we have to remember, all right? And that's it. All right. Thank you. Thank you.
what they do. And Rails components in general can you can use Active Record outside Rails. You can together. And we are going to see how that works. is generated, but in any, at least modern Rails then does something. Config environment is summary of what we have seen up to this point. So things to do when you boot. One of them is have as a boot process as lightweight as of an application, that's the idea for an engine. some configuration and some initializers for paths, locale, a number of things. Okay? So it is whatever. And then some other paths. Then you Okay, the definition of the application class