RailsConf 2016
Rediscovering Active Record

Rediscovering Active Record

by Mario Alberto Chavez

In the presentation titled "Rediscovering Active Record," Mario Alberto Chavez explores the inner workings of the Active Record component of Rails, debunking the myth of its 'magic.' He emphasizes the necessity for Rails developers to understand how Active Record transforms database queries into objects and functionally operates with the database.

Key Points Discussed:
- Understanding Active Record: Active Record is more than just a framework feature; it simplifies database interaction by handling complexities that arise in connecting models to database tables.
- Schema Introspection: Active Record automatically retrieves and caches the database schema the first time a model is accessed, significantly improving performance in subsequent queries.
- Data Type Casting: Active Record manages data type casting from database formats to Ruby types. Custom data types can be created in Rails by implementing methods like serialize and cast.
- Lazy Loading Mechanism: Active Record utilizes lazy loading to prepare queries without executing them immediately, optimizing resource usage.
- Efficient Query Execution: When a query is executed, Active Record builds the SQL statement, binds parameters securely, and converts the result set into model instances, facilitating intuitive data manipulation.
- Exploration Encouraged: Mario urges developers to delve deeper into the Rails framework to uncover valuable insights and improve their efficiency.

Throughout the talk, Mario shares his personal experience with Active Record, illustrating the significance of understanding the framework's mechanics to enhance development practices. He concludes by advocating for ongoing curiosity and hands-on exploration, encouraging developers to engage with the Rails ecosystem, whether through documentation, testing, or community resources.

Ultimately, gaining a solid grasp of Active Record's operations not only demystifies its processes but also unlocks new potential for developers using Rails.

00:00:09.960 My name is Mario Alberto Chavez, and I work for a development company. Today, I'm going to talk about rediscovering Active Record.
00:00:15.000 We are all familiar with Active Record. When I came to Rails years ago, the first thing I heard from people was that it was magic.
00:00:21.560 So let's get started. We just create or define a class, which is basically what we needed in order to work with a database.
00:00:29.920 However, over time, I found that there is no magic in Active Record. Active Record does some pretty cool things for us, hiding a lot of the complexity that comes from having a model connected to a table in the database. But in the end, there is no magic at all. What I want to do here is to explore the main actions that Active Record performs to transform a query into an object.
00:00:57.960 Let's start with a function that I'm sure we are all familiar with. You can think of it like a Russian doll. We are basically just using a generator. What we are going to end up with is something like this. I started with building gems, accessed autoloading magic, and opened up the console. I can run a query asking Active Record to access the database and pull a record with a specific ID. What we see below is the actual response.
00:01:39.560 In this case, I have an ID, name, and email address. Obviously, we will also have standard CRUD operations. But how can Active Record come from this to being able to execute? What is doing all the magic?
00:02:08.479 The first thing we need to understand is that Active Record needs to perform some kind of introspection. With this introspection, the first task that Active Record will perform is to ask the database what the schema is. Once we have this table schema, we can do a lot of things.
00:02:45.800 The first time we load JavaScript or CSS in our application and we attempt to execute any kind of operation like a query, the first action that will happen is that Active Record will try to load the necessary schema for that model. Basically, what it's doing is calling a method. If we fire up the console and use a model to call this attribute types method, we will find out that this method triggers something inside the Active Record code called 'load schema.' This method delegates the call to the actual database connection to ask for the schema relevant to that model.
00:03:21.959 So, every time—or at least the first time—we try to use a model, Active Record will go in, pull the table schema, make a copy of it, and cache it, making it ready for the next calls to these models. This means that only the first time for each model, we will perform this operation, effectively caching the schema so that subsequent calls don’t need to go to the database for it.
00:04:05.200 For example, if we call the schema cache column hash for the users table, we will retrieve a specific hash. The keys will be the columns of the table, and the values will be objects carrying a lot of information. Some important pieces of data we receive here include the attribute type. We can see that the database might be an integer type, but there will also be default values and other important metadata that we can use within Active Record.
00:05:16.120 Now that we see this cache schema method, it also needs to give us some extra information. Basically, what we need is a cast type. A cast type allows us to convert whatever the database tells us about the data type we are storing into how it should be represented on the Ruby side.
00:06:06.400 In the case of integers, for example, the transformation is straightforward—when we have an integer in the database, it practically remains an integer in Ruby. However, for complex data types like timestamps, we require a system to manage that casting.
00:06:39.840 Inside Active Record, it implements a base class to manage type casting. It typically has types such as active model type integer, string, date, among others, that help facilitate this process. Implemented in Rails 5, we can also create our own custom types. For instance, if we have a field in the database storing complex data, we might want to translate that into an object in our application. This custom data type does not necessarily have to be an Active Record model; it could be a struct or any type compatible with Rails.
00:07:21.680 In order to define our own data types in Rails, we need to implement at least three methods: serialize, cast, and the third is up to us. The serialize method specifies how we convert data from the database into a Ruby object. The cast method is used for user input to convert it from whatever format the user provides into the type stored in the database. Finally, we have the cast method, which defines how we convert Ruby types back into the database's data type.
00:08:00.760 Active Record has a way to pull the database schema. Now I just want to show one more thing, which is how Active Record provides this lazy loading mechanism. When we invoke something like attribute types, we are basically asking to see the response for what’s available in our model.
00:08:59.000 Inside this, we can still understand the schema, but we cannot actually run the query just yet. The actual query that needs to be performed requires us to create it. Active Record is smart enough to allow the creation of query objects for us.
00:09:21.360 When we execute a query, for example using the find method, it tries to see if that previous statement was executed before. If it has, it pulls that query without executing it again. If not, the find method converts the request into a new environment—everything gets wrapped inside a block.
00:11:05.000 In this block, we define the query, and Active Record works under the hood to convert that into SQL. When we want to retrieve, Active Record constructs the appropriate SQL statement for us.
00:11:49.600 The statement will then have placeholders, which means that when we execute our SQL queries, Rails takes care to bind values to these parameters. This method performs essential steps where the SQL gets prepared and executed without needing to define everything at once. It ensures that we efficiently retrieve only what we need and allows us to map results back into our Active Record objects.
00:12:57.360 Finalizing execution involves calling the execute method, which pulls the required ID for the record we want from the database. This will return a result set, which consists of rows and columns arranged in a structured manner.
00:14:05.559 Active Record then transforms this result set into instances of our models, effectively creating the objects that represent our data in a way that feels intuitive to work with.
00:15:16.839 From here, it has to allocate model objects and initialize attributes—making sure that for each record queried, the appropriate accessors are defined. When initializing attributes, Active Record checks if the attributes have already been set and will create the necessary methods on the fly.
00:16:10.759 This process is foundational to how we interact with our models, and it engages a whole series of internal processes that handle caching and efficient data retrieval.
00:16:57.680 Through all these unique steps, what we can see ultimately is that while Active Record does seem magical, it is simply performing a series of well-structured tasks that efficiently interacts with our database.
00:18:12.920 The key takeaway here is that understanding how Active Record works underneath the surface can enhance our effectiveness as developers. Curious exploration into the Rails framework can yield improvement in our development process.
00:19:33.400 As I was diving into this code, I discovered the intricate workings of Active Record, prompting me to share my insights. If you're interested in how Active Record operates, it’s worth taking the time to explore.
00:20:00.799 I encourage you to think of your tools with curiosity and dive deeper into their contexts. Whether through documentation, GitHub repositories, or simply testing out queries in a console, the experience can often be quite rewarding.
00:21:35.740 Thank you for being here today, and I hope you can take these insights back into your work with Rails. If there are any questions about Rails engines, feel free to ask.