Rediscovering ActiveRecord
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Chavez, Mario Alberto
Being a Rails developer is more than just understanding how to use the Framework to develop applications. To become an efficient developer, you should learn how the Framework works; how deep this understanding should be is up to you. Exploring the Framework code is something that everyone should do at least once. Not only may you learn how it works but also, you might learn new tricks from the code itself or discover small features that are not widely publicized.
 My name is Mero Chavez. I work for development shop. You have them all working? The name of the company is Chara.io. And what I'm going to talk today is about rediscovering active record. So probably we are all familiar with active record. When I came to Rails like eight years ago, the first thing that I hear from the people is what was active record was magic. Let's get started. We just create or define a class. How I started putting this. That's pretty much what we needed in order to make it work professionally about two years ago. But over time, I just find out that actually there is no magic in active record. Active record is doing pretty cool things for us. It's hiding a lot of the complexity that implies to have a model be connected to a table in the database. But at the end, there is no magic at all. What I'm trying to do here is just to do some exploration and go to the main actions that active record is doing for us in order to transform the query into an object. So let's start with that. Many of the applications that provide function. Probably we are all familiar with this line of code. It has like a Russian dollar, right? We are basically just using a generator in order to break the model. But we are going to end up with something like this. Again, it's just a fast operation. But you build gems, so it's still loading magic. And if I open up the console, I can run this query where I'm asking active record to go to the database and pull one of the records with the ID one. Absolutely, what we see below is the actual response that we probably work with the tools on the screen. In this case, I have an ID, I have a name, an email address, and obviously we're going to have the created and updated type of stuff. But the question here is how you have on the top record doing this. How can active record come from this into being able to execute my query? What is it doing? How they're doing all their magic and reading points and views? The first thing that we need to understand is that active record needs to do some kind of introspection. You'll still understand just how you're working out. With introspection, the first thing that active record needs to perform is to ask the database what is the table schema? Once that we have this table schema, then we can do a lot of things. So the first thing that we load a model on our application and we try to do any kind of operations like a query, the first thing that is going to happen is that active record is going to try to load this schema. Basically what it's doing, it's calling this method. If we fire up the console and we just use a model and call these attribute types, what we are going to find out is that this method, it's going to fire something inside of the active record code which is called load schema. No we cannot build a load application. This method is delegating the call to the actual connection, the actual database connection to ask what is the schema for this specific model. Here the connection is laying on the schema cache. So it means that every time or at least the first time that we try to use a model, active record is going to go in there, pull the table schema, made a copy of that, cache it and leave it ready for us for the next calls to this model. So it means that only the first time for each model we are going to make this kind of call. Also this means that the connection is keeping the hash. If this hash, it contains all the attributes, all the schema for this specific model. We can see, for example, in this piece of code, we are expecting, we are asking the hash to give us the schema for a specific table. If there is nothing in there, that's where the connection actually issue a query to the database. It will depend on each database how the query is going to look like. But at the end we are going to get all the information that we need to understand what is the schema for our model. So you can roll the Rails application. What we are getting, if we call directly the schema cache column hash, for example, for the table user, we are going to get this specific hash. We have the keys are going to be the columns of the table. And the value is going to be an object that it's going to have a lot of information. But probably some of the most important piece of data that we are getting here is the attribute type. We can see here that the database is an integer. But also we are going to have the default values and any other important information that we can use inside of ActiveRecord. Now that we have this understanding, the low-taskimmetals also needs to give us a little more information from the Ruby side. Basically what we are going to need is going to need a cache type. And a cache type is something that will allow us to convert whatever the database is telling us that it's going to be the data type that we are storing the database and what the data type is going to become on the Ruby side. Obviously for integer, probably this is pretty simple. I mean, if we have a number, we're going to have, if we have an integer in the database, probably we're going to have an integer on the Ruby side. But for things like, for example, timestamps, this is going to be a different story. We're going to need something that will help us to make the cache between the original data type into a Ruby type. Here's what I'm going to do. What is happening inside of ActiveRecord is that it does implement this active model type value. This is a base class that helps define how ActiveRecord is going to make this casting between database types into Ruby types. If we inspect the ActiveRecord source code, we're going to find out that we have active model type integer, active model type string, active model type date, and some other objects that will help us to create this cast. This is something new in Rails 5. Well, actually, it is implemented in Rails. It looks like it actually called our lambda. But the API is private. It's not available for us. But in Rails 5, we can actually create our own types. For example, imagine that we have a field in the database where we are storing an edge store data in there. And then we want to pull the data into our Rails application. But instead of getting a hash, we wanted to convert that into some sort of object. And this object doesn't really need to be an active model object. It can be pretty much everything. Or probably we can convert that into an extract or something like that. So we can actually define our own data types for Rails. And the way that we can do that is we need to implement at least three methods from this type of class. The first one is serialize. This is the method that we are going to tell Rails or ActiveRecord how we are going to transform whatever we are getting from the database into a Ruby object. The second one is cast. This one is being used for user input. For example, it says that we have a form and in the form we have an input field. And this input field can accept a number. When the form posts that information back to Rails, we need a way to get the number and convert it into the final type that is going to be stored in the database. And finally, we need to implement the serialize method. I don't think that's going to be one of the things that's going to be used. Let's just try to get it right. Why not? The Ruby type data is going to be transformed into the database type. So as I said, this is part of the attributes API. Without using models or controllers. So at this point, now that we were able to pull the database schema. Now I just want to do one more thing which will hopefully be of interest. A casting type for ActiveRecord or model will be able to understand what is the scheme. If we call these attributes types, we can see here the response. So look at that. So what now? We know that we can understand the schema, but we cannot still get to this point where we actually run the query. The next thing that the ActiveRecord needs to perform is to create a query for us. Here's the cookie information. ActiveRecord is smart enough to try to cache query objects for us. Let me explain why. When we execute a query, for example, this dot find and the number, what it's going to do, it's going to try to find if that statement has been executed before. If it is, obviously, we're going to just pull the query and we're going to perform whatever action it needs to be done. But if not, then our find method is going to be converted into a word. So we can see here in the block, that's the query. That's how the find number, dot find ID is being converted into a query. But there's something here that we need to pay attention is that in the word calls, instead of passing the ID of the object that I'm looking for, Rails or ActiveRecord is doing something params.by. And we're going to see what it means in a minute. So we don't have the query. It means that we're going to have to create a new one. If we go to the statement cache file, we're going to have find this method. And this is the part that takes care of creating the query for us. The first thing that we are going to need is to convert the dot word into RL's AST. And that's what the first line of the create method is doing. This block.call is actually executing the word clause that we see before. And this word clause is being converted into this RL3 where we have this node which is equality. We have the attribute, which is the attribute ID. And then on the right side, we have something called bind param. This is kind of a placeholder where we're going to replace that with the ID of the object that we are looking for. And actually, if we see the other structure that we have on the left, we see at the end that we have a block which reference to the ID. But instead of saying that it's an integer or displaying the value, what it's actually saying is that this is a substitute. This is something that we are going to replace at some point. The next part that we need to, or that the create method is doing here is to screen a bind map. The bind map is basically setting up what are the params that we are going to pass to the query. The first one on the right is the value for the limit clause because we are doing dot find and we are actually asking for just one record and the one on the left is the definition just for the query attribute in this case is the ID field. So when we go to slash foo, the path info is slash foo, it goes back. You go to slash bo- The next thing that's going to happen here is that we're going to create this query builder of the RLST. This is what actually is going to construct a TSQL for us. In this case, it is using the specific database adapter in order to create the right query for the right database. So in my case, I was using Postgres. If we were using MySQL or something else, the query probably will be a little bit different. But here, what we can see in the query that this query builder is screened for us is that the ID and the limit has these question marks, which means that those are placeholders that we're going to replace at some point. And doing this will allow us also to cache the query on the rail size, but also we are going to give the chance on the database to cache the query, the execution plan for the query in the database. So you can have any kind of rack. You made up with me up to this point. The model knows what is the schema. We know that we need to build a query. Web interface. So what is next? We're almost there. But if you are running, still not there. Many of you are. At this point, we are ready to execute the query. What is going to happen is that now that we have the statement, we're going to be able to call this method execute. And the method execute, as you can see, one of the patterns is the actual ID that we are trying to, you can mount the record that we are trying to pull from the database. And well, we also pass in the connection. The execute method will do a couple things here. The first step, it's going to actually perform the binds. Do you remember? In the previous steps, we have a bind map and we have two attributes in there. The first one was the limit clause and the second one was for the ID. But at that point, the ID was marked as a substitute. At this point, we are actually replacing the value with the real ID of the record that we are trying to pull here. Rails engine. So what's the thing? Rails application are... What we are asking in this step is to actually give us the SQL statement, the string that we are going to send to the database. We see that we still have the placeholders. What are Rails engines then? And once that we are ready, what Active Record is going to do is just execute this find by SQL where we are actually going to pass the SQL query, the bind values, which are the values that at the end are going to be sent to the database for a query. And you can mount in the Rails application. What we are going to get is, at some point, is a result set. This result set, it's going to be something like this. Our miniature application is just an object that has columns and rows. And for the rows, it's an array of arrays. So on the last step, what we are going to perform is we are going to execute a map of this result set. And the instantiate method is the one that is going to create the instances for each one of the records that we are pulling off the database. That would feel too distant from reality. It's to feel like we know we might want to do something like this. So the instantiate method, those a few things. The first thing is that it needs to allocate the object, like actually create the object of the user model. And then it needs to initialize the attributes. And this is an important step. Actually the code for initializing the attributes is the one that you are seeing here. So it's a few. The first thing that we, that ActiveRecord needs to perform is to define all the accessors and the helper methods for the app. Like for example, this is the first time that we use this model. So it doesn't have like a dot name or dot email. And this is where those methods are going to be defined. Inside of the model, there is a flag that says if all the attributes have been initialized or not, if not, then there is something that runs and create all these methods and all the query methods also. The logic for this is if you want to look into the source code, it's the attribute methods. Actually the logic is very dense and probably it needs a talk by its own because it's ActiveRecord is performing a lot of work in there. But anyhow, now that we have all the attributes, the next thing that we need to set for the model is to create this lazy attribute hash. This lazy attribute hash is every time that we call like a user dot attributes, actually we are delegating that call into this class. And this class is the one that knows what is the data that our model is containing or object is holding on. It's fine, don't worry about it. If we inspect this lazy attribute hash, we're going to find out that it has two main variables here. The first one is the types. Do you remember at some point I told you that once that we get the schema, we need a cast type and this cast type is the way that we're allowed to convert the data from the database into a Ruby type. So here we have this hash where we can see each of the attributes, what is the cast type that is going to be used. And also we have the values. The values is where we are actually holding the data as it comes from the database. There is no transformation here. There is nothing that we haven't made to the data yet. It's just the raw data that we get from the database. The name of this class, lazy attribute hash, it has a meaning. Because let's say that our model has 10 attributes and we do user.find1 and we get the model. So if we wanted to cast all the data for the 10 attributes, just as soon as we get the data, obviously we're going to spend time over there just doing the casting in order to prepare the data to be used by us. But for example, what lazy attribute hash is doing is that it is delaying that. If we just do user.find1, we're going to get the model, but no casting is going to be performed. Until we do something like a user.name and we try to pull the name, then that's when the lazy attribute hash is going to perform the casting. This is the same for the rest of the attributes. So once that we do something like a user.id, as you can see, there is another variable inside of the lazy attribute hash, which is the delegate hash. And this one is actually containing the value that it comes as a raw value from the database and the final value as it was casted. For example, if this were the example of the timestamp, we're going to see on the value before cast that it was just in a string and the value will be the actual Ruby type that represents the data. Things go wrong because they during. So, yes, it's working lazy. So finally, after going through all these hoops, Active Record was able to perform the query that I asked for and I got the expected result. So as you can see, there is a lot of work that is involved in order to go from just class, user declaration to actually having Active Record perform something for us. So what we learned here, the first thing again is that there is no magic. What Active Record is doing actually a pretty cool thing. Obviously what I show you here were mostly the highlights. But following the code is not that hard. It's actually pretty easy to just pick up one of the query and try to follow up. Whatever Active Record is doing underneath. Another thing that I learned what I was doing this is that Active Record is going to try to cache and be as lazy as possible. Every time that we work with the models, if there is a work that doesn't need to be performed like a right away, Active Record is going to just put in a hold and then do something else until we actually require that. And if there is a chance for Active Record to actually cache whatever we are doing into the different operations, then Active Record is going to try to cache that information for us. And well, as I said, following the code is not that hard. We don't really need to go deep into understanding how all the things work in the framework. But obviously, we need to have some sort of curiosity with the tools that we use every day just to get a great idea on what's there, what is going on, how things work. I got interested in this because I was writing a blog post probably two weeks before the first beta one of Rails 5 hits. So I was going through all the different pull requests on GitHub and I find out a lot of things that were happening inside of Active Record. And that's how I just started off with the curiosity to see what is happening inside of Active Record every time that we run the query. So the first thing that you'll notice is that it is a gem. We do have our gem stuff. So this is kind of like the... I don't know if you have any questions. There are Rails engines that you can search for other places. Sorry, one more thing to mention about that gem spec, kind of important. Well, there is... Oh, yes. If there is any other resources other than just going directly to the code, if... If you want to learn or to understand what is going with Active Record. Sure, there is an IRC. There are Google groups also going directly to the GitHub. And we're going to be working with the gem spec as we go on. If you look in lib, you'll see the name of the gem back and everything is going to be named as a module, which is why you have a name space back there. Everything in this engine is going to be namespaced and we'll see how that plays out. And because there's an engine, it's for Rails engine, that's the thing that tells Rails, okay, treat this as an engine. There are routes that are being... Which you'll see is not on a real... Is your engine, right? We had our... No, sorry. I never been in that specific situation. When... These are requests. Yes, sorry. Level like... I'm like my own... Okay, so we're going to work with the file a lot. Thank you. And you have property. Thank you.
 My name is Mero Chavez.  I work for development shop.  You have them all working?  The name of the company is Chara.io.  And what I'm going to talk today is about rediscovering active record.  So probably we are all familiar with active record.  When I came to Rails like eight years ago, the first thing that I hear from the people  is what was active record was magic.  Let's get started.  We just create or define a class.  How I started putting this.  That's pretty much what we needed in order to make it work professionally about two  years ago.  But over time, I just find out that actually there is no magic in active record.  Active record is doing pretty cool things for us.  It's hiding a lot of the complexity that implies to have a model be connected to a  table in the database.  But at the end, there is no magic at all.  What I'm trying to do here is just to do some exploration and go to the main actions that  active record is doing for us in order to transform the query into an object.  So let's start with that.  Many of the applications that provide function.  Probably we are all familiar with this line of code.  It has like a Russian dollar, right?  We are basically just using a generator in order to break the model.  But we are going to end up with something like this.  Again, it's just a fast operation.  But you build gems, so it's still loading magic.  And if I open up the console, I can run this query where I'm asking active record to go  to the database and pull one of the records with the ID one.  Absolutely, what we see below is the actual response that we probably work with the tools  on the screen.  In this case, I have an ID, I have a name, an email address, and obviously we're going  to have the created and updated type of stuff.  But the question here is how you have on the top record doing this.  How can active record come from this into being able to execute my query?  What is it doing?  How they're doing all their magic and reading points and views?  The first thing that we need to understand is that active record needs to do some kind  of introspection.  You'll still understand just how you're working out.  With introspection, the first thing that active record needs to perform is to ask the  database what is the table schema?  Once that we have this table schema, then we can do a lot of things.  So the first thing that we load a model on our application and we try to do any kind  of operations like a query, the first thing that is going to happen is that active record  is going to try to load this schema.  Basically what it's doing, it's calling this method.  If we fire up the console and we just use a model and call these attribute types, what  we are going to find out is that this method, it's going to fire something inside of the  active record code which is called load schema.  No we cannot build a load application.  This method is delegating the call to the actual connection, the actual database connection  to ask what is the schema for this specific model.  Here the connection is laying on the schema cache.  So it means that every time or at least the first time that we try to use a model, active  record is going to go in there, pull the table schema, made a copy of that, cache it and  leave it ready for us for the next calls to this model.  So it means that only the first time for each model we are going to make this kind of call.  Also this means that the connection is keeping the hash.  If this hash, it contains all the attributes, all the schema for this specific model.  We can see, for example, in this piece of code, we are expecting, we are asking the  hash to give us the schema for a specific table.  If there is nothing in there, that's where the connection actually issue a query to  the database.  It will depend on each database how the query is going to look like.  But at the end we are going to get all the information that we need to understand what  is the schema for our model.  So you can roll the Rails application.  What we are getting, if we call directly the schema cache column hash, for example, for  the table user, we are going to get this specific hash.  We have the keys are going to be the columns of the table.  And the value is going to be an object that it's going to have a lot of information.  But probably some of the most important piece of data that we are getting here is the attribute  type.  We can see here that the database is an integer.  But also we are going to have the default values and any other important information  that we can use inside of ActiveRecord.  Now that we have this understanding, the low-taskimmetals also needs to give us a little more information  from the Ruby side.  Basically what we are going to need is going to need a cache type.  And a cache type is something that will allow us to convert whatever the database is telling  us that it's going to be the data type that we are storing the database and what the data  type is going to become on the Ruby side.  Obviously for integer, probably this is pretty simple.  I mean, if we have a number, we're going to have, if we have an integer in the database,  probably we're going to have an integer on the Ruby side.  But for things like, for example, timestamps, this is going to be a different story.  We're going to need something that will help us to make the cache between the original  data type into a Ruby type.  Here's what I'm going to do.  What is happening inside of ActiveRecord is that it does implement this active model  type value.  This is a base class that helps define how ActiveRecord is going to make this casting  between database types into Ruby types.  If we inspect the ActiveRecord source code, we're going to find out that we have active  model type integer, active model type string, active model type date, and some other objects  that will help us to create this cast.  This is something new in Rails 5.  Well, actually, it is implemented in Rails.  It looks like it actually called our lambda.  But the API is private.  It's not available for us.  But in Rails 5, we can actually create our own types.  For example, imagine that we have a field in the database where we are storing an edge  store data in there.  And then we want to pull the data into our Rails application.  But instead of getting a hash, we wanted to convert that into some sort of object.  And this object doesn't really need to be an active model object.  It can be pretty much everything.  Or probably we can convert that into an extract or something like that.  So we can actually define our own data types for Rails.  And the way that we can do that is we need to implement at least three methods from this  type of class.  The first one is serialize.  This is the method that we are going to tell Rails or ActiveRecord how we are going to  transform whatever we are getting from the database into a Ruby object.  The second one is cast.  This one is being used for user input.  For example, it says that we have a form and in the form we have an input field.  And this input field can accept a number.  When the form posts that information back to Rails, we need a way to get the number  and convert it into the final type that is going to be stored in the database.  And finally, we need to implement the serialize method.  I don't think that's going to be one of the things that's going to be used.  Let's just try to get it right.  Why not?  The Ruby type data is going to be transformed into the database type.  So as I said, this is part of the attributes API.  Without using models or controllers.  So at this point, now that we were able to pull the database schema.  Now I just want to do one more thing which will hopefully be of interest.  A casting type for ActiveRecord or model will be able to understand what is the scheme.  If we call these attributes types, we can see here the response.  So look at that.  So what now?  We know that we can understand the schema, but we cannot still get to this point where  we actually run the query.  The next thing that the ActiveRecord needs to perform is to create a query for us.  Here's the cookie information.  ActiveRecord is smart enough to try to cache query objects for us.  Let me explain why.  When we execute a query, for example, this dot find and the number, what it's going  to do, it's going to try to find if that statement has been executed before.  If it is, obviously, we're going to just pull the query and we're going to perform whatever  action it needs to be done.  But if not, then our find method is going to be converted into a word.  So we can see here in the block, that's the query.  That's how the find number, dot find ID is being converted into a query.  But there's something here that we need to pay attention is that in the word calls, instead  of passing the ID of the object that I'm looking for, Rails or ActiveRecord is doing something  params.by.  And we're going to see what it means in a minute.  So we don't have the query.  It means that we're going to have to create a new one.  If we go to the statement cache file, we're going to have find this method.  And this is the part that takes care of creating the query for us.  The first thing that we are going to need is to convert the dot word into RL's AST.  And that's what the first line of the create method is doing.  This block.call is actually executing the word clause that we see before.  And this word clause is being converted into this RL3 where we have this node which is  equality.  We have the attribute, which is the attribute ID.  And then on the right side, we have something called bind param.  This is kind of a placeholder where we're going to replace that with the ID of the object  that we are looking for.  And actually, if we see the other structure that we have on the left, we see at the end  that we have a block which reference to the ID.  But instead of saying that it's an integer or displaying the value, what it's actually  saying is that this is a substitute.  This is something that we are going to replace at some point.  The next part that we need to, or that the create method is doing here is to screen a  bind map.  The bind map is basically setting up what are the params that we are going to pass to  the query.  The first one on the right is the value for the limit clause because we are doing dot  find and we are actually asking for just one record and the one on the left is the definition  just for the query attribute in this case is the ID field.  So when we go to slash foo, the path info is slash foo, it goes back.  You go to slash bo-  The next thing that's going to happen here is that we're going to create this query  builder of the RLST.  This is what actually is going to construct a TSQL for us.  In this case, it is using the specific database adapter in order to create the right query  for the right database.  So in my case, I was using Postgres.  If we were using MySQL or something else, the query probably will be a little bit different.  But here, what we can see in the query that this query builder is screened for us is that  the ID and the limit has these question marks, which means that those are placeholders that  we're going to replace at some point.  And doing this will allow us also to cache the query on the rail size, but also we are  going to give the chance on the database to cache the query, the execution plan for the  query in the database.  So you can have any kind of rack.  You made up with me up to this point.  The model knows what is the schema.  We know that we need to build a query.  Web interface.  So what is next?  We're almost there.  But if you are running, still not there.  Many of you are.  At this point, we are ready to execute the query.  What is going to happen is that now that we have the statement, we're going to be able  to call this method execute.  And the method execute, as you can see, one of the patterns is the actual ID that we are  trying to, you can mount the record that we are trying to pull from the database.  And well, we also pass in the connection.  The execute method will do a couple things here.  The first step, it's going to actually perform the binds.  Do you remember?  In the previous steps, we have a bind map and we have two attributes in there.  The first one was the limit clause and the second one was for the ID.  But at that point, the ID was marked as a substitute.  At this point, we are actually replacing the value with the real ID of the record that  we are trying to pull here.  Rails engine.  So what's the thing?  Rails application are...  What we are asking in this step is to actually give us the SQL statement, the string that  we are going to send to the database.  We see that we still have the placeholders.  What are Rails engines then?  And once that we are ready, what Active Record is going to do is just execute this find by  SQL where we are actually going to pass the SQL query, the bind values, which are the  values that at the end are going to be sent to the database for a query.  And you can mount in the Rails application.  What we are going to get is, at some point, is a result set.  This result set, it's going to be something like this.  Our miniature application is just an object that has columns and rows.  And for the rows, it's an array of arrays.  So on the last step, what we are going to perform is we are going to execute a map of  this result set.  And the instantiate method is the one that is going to create the instances for each  one of the records that we are pulling off the database.  That would feel too distant from reality.  It's to feel like we know we might want to do something like this.  So the instantiate method, those a few things.  The first thing is that it needs to allocate the object, like actually create the object  of the user model.  And then it needs to initialize the attributes.  And this is an important step.  Actually the code for initializing the attributes is the one that you are seeing here.  So it's a few.  The first thing that we, that ActiveRecord needs to perform is to define all the accessors  and the helper methods for the app.  Like for example, this is the first time that we use this model.  So it doesn't have like a dot name or dot email.  And this is where those methods are going to be defined.  Inside of the model, there is a flag that says if all the attributes have been initialized  or not, if not, then there is something that runs and create all these methods and all  the query methods also.  The logic for this is if you want to look into the source code, it's the attribute methods.  Actually the logic is very dense and probably it needs a talk by its own because it's ActiveRecord  is performing a lot of work in there.  But anyhow, now that we have all the attributes, the next thing that we need to set for the  model is to create this lazy attribute hash.  This lazy attribute hash is every time that we call like a user dot attributes, actually  we are delegating that call into this class.  And this class is the one that knows what is the data that our model is containing or  object is holding on.  It's fine, don't worry about it.  If we inspect this lazy attribute hash, we're going to find out that it has two main variables  here.  The first one is the types.  Do you remember at some point I told you that once that we get the schema, we need a  cast type and this cast type is the way that we're allowed to convert the data from the  database into a Ruby type.  So here we have this hash where we can see each of the attributes, what is the cast type  that is going to be used.  And also we have the values.  The values is where we are actually holding the data as it comes from the database.  There is no transformation here.  There is nothing that we haven't made to the data yet.  It's just the raw data that we get from the database.  The name of this class, lazy attribute hash, it has a meaning.  Because let's say that our model has 10 attributes and we do user.find1 and we get the model.  So if we wanted to cast all the data for the 10 attributes, just as soon as we get the  data, obviously we're going to spend time over there just doing the casting in order  to prepare the data to be used by us.  But for example, what lazy attribute hash is doing is that it is delaying that.  If we just do user.find1, we're going to get the model, but no casting is going to  be performed.  Until we do something like a user.name and we try to pull the name, then that's when  the lazy attribute hash is going to perform the casting.  This is the same for the rest of the attributes.  So once that we do something like a user.id, as you can see, there is another variable  inside of the lazy attribute hash, which is the delegate hash.  And this one is actually containing the value that it comes as a raw value from the database  and the final value as it was casted.  For example, if this were the example of the timestamp, we're going to see on the value  before cast that it was just in a string and the value will be the actual Ruby type that  represents the data.  Things go wrong because they during.  So, yes, it's working lazy.  So finally, after going through all these hoops, Active Record was able to perform the  query that I asked for and I got the expected result.  So as you can see, there is a lot of work that is involved in order to go from just  class, user declaration to actually having Active Record perform something for us.  So what we learned here, the first thing again is that there is no magic.  What Active Record is doing actually a pretty cool thing.  Obviously what I show you here were mostly the highlights.  But following the code is not that hard.  It's actually pretty easy to just pick up one of the query and try to follow up.  Whatever Active Record is doing underneath.  Another thing that I learned what I was doing this is that Active Record is going to try  to cache and be as lazy as possible.  Every time that we work with the models, if there is a work that doesn't need to be performed  like a right away, Active Record is going to just put in a hold and then do something  else until we actually require that.  And if there is a chance for Active Record to actually cache whatever we are doing into  the different operations, then Active Record is going to try to cache that information  for us.  And well, as I said, following the code is not that hard.  We don't really need to go deep into understanding how all the things work in the framework.  But obviously, we need to have some sort of curiosity with the tools that we use every  day just to get a great idea on what's there, what is going on, how things work.  I got interested in this because I was writing a blog post probably two weeks before the  first beta one of Rails 5 hits.  So I was going through all the different pull requests on GitHub and I find out a lot of  things that were happening inside of Active Record.  And that's how I just started off with the curiosity to see what is happening inside  of Active Record every time that we run the query.  So the first thing that you'll notice is that it is a gem.  We do have our gem stuff.  So this is kind of like the...  I don't know if you have any questions.  There are Rails engines that you can search for other places.  Sorry, one more thing to mention about that gem spec, kind of important.  Well, there is...  Oh, yes.  If there is any other resources other than just going directly to the code, if...  If you want to learn or to understand what is going with Active Record.  Sure, there is an IRC.  There are Google groups also going directly to the GitHub.  And we're going to be working with the gem spec as we go on.  If you look in lib, you'll see the name of the gem back and everything is going to be  named as a module, which is why you have a name space back there.  Everything in this engine is going to be namespaced and we'll see how that plays out.  And because there's an engine, it's for Rails engine, that's the thing that tells Rails,  okay, treat this as an engine.  There are routes that are being...  Which you'll see is not on a real...  Is your engine, right?  We had our...  No, sorry.  I never been in that specific situation.  When...  These are requests.  Yes, sorry.  Level like...  I'm like my own...  Okay, so we're going to work with the file a lot.  Thank you.  And you have property.  Thank you.
Rediscovering_ActiveRecord_0_59.png Rediscovering_ActiveRecord_60_119.png Rediscovering_ActiveRecord_120_239.png Rediscovering_ActiveRecord_240_635.png Rediscovering_ActiveRecord_636_1931.png Rediscovering_ActiveRecord_1932_2447.png Rediscovering_ActiveRecord_2448_3671.png Rediscovering_ActiveRecord_3672_3791.png Rediscovering_ActiveRecord_3792_4019.png Rediscovering_ActiveRecord_4020_5519.png Rediscovering_ActiveRecord_5520_6791.png Rediscovering_ActiveRecord_6792_7907.png Rediscovering_ActiveRecord_7908_10547.png Rediscovering_ActiveRecord_10548_14543.png Rediscovering_ActiveRecord_14544_15191.png Rediscovering_ActiveRecord_15192_15323.png Rediscovering_ActiveRecord_15324_15467.png Rediscovering_ActiveRecord_15468_15683.png Rediscovering_ActiveRecord_15684_17471.png Rediscovering_ActiveRecord_17472_18131.png Rediscovering_ActiveRecord_18132_19631.png Rediscovering_ActiveRecord_19632_20519.png Rediscovering_ActiveRecord_20520_22139.png Rediscovering_ActiveRecord_22140_22211.png Rediscovering_ActiveRecord_22212_22679.png Rediscovering_ActiveRecord_22680_22751.png Rediscovering_ActiveRecord_22752_22835.png Rediscovering_ActiveRecord_22836_23543.png Rediscovering_ActiveRecord_23544_24311.png Rediscovering_ActiveRecord_24312_25703.png Rediscovering_ActiveRecord_25704_26183.png Rediscovering_ActiveRecord_26184_26231.png Rediscovering_ActiveRecord_26232_26279.png Rediscovering_ActiveRecord_26280_26735.png Rediscovering_ActiveRecord_26736_33011.png Rediscovering_ActiveRecord_33012_33839.png Rediscovering_ActiveRecord_33840_37211.png Rediscovering_ActiveRecord_37212_40559.png Rediscovering_ActiveRecord_40560_40679.png Rediscovering_ActiveRecord_40680_40811.png Rediscovering_ActiveRecord_40812_40826.png