Active Record Flashcards
What is Active Record?
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database. It is an implementation of the Active Record pattern which itself is a description of an Object Relational Mapping system.
What is the Active Record Pattern?
In Active Record, objects carry both persistent data and behavior which operates on that data. Active Record takes the opinion that ensuring data access logic as part of the object will educate users of that object on how to write to and read from the database.
Active Record as an ORM Framework
Represent models and their data.
Represent associations between these models.
Represent inheritance hierarchies through related models.
Validate models before they get persisted to the database.
Perform database operations in an object-oriented fashion.
How do we create Active Record Models?
What is an example?
Subclass the ApplicationRecord:
class Product < ApplicationRecord end
This will create a Product model, mapped to a products table at the database. By doing this you’ll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. Suppose that the products table was created using an SQL statement like:
CREATE TABLE products ( id int(11) NOT NULL auto_increment, name varchar(255), PRIMARY KEY (id) );
Describe ActiveRecord::Base
Application Record inherits from ActiveRecord::Base, with has many methods:
.table_name
.set_fixture_class
What are some typical AR methods?
.where .select .joins .order .limit
** REMEBER to pass in symbols of tablenames an not strings **
What is an N+1 Query? (aka N+1 Selects)? And how do we use ‘includes’ or ‘joins’ to make it faster?
N + 1 query is when a query is performed once for each request. Each db query had overhead. so this can be very wasteful.
includes
prefetches the association comments
, so it doesn’t need to be queried for later. includes
does not change the type of the object returned (in this example, Post
s); it only prefetches extra data. It still run in the similar amount of time but it doesnt hit the DB.
We use includes
when we need to prefetch an association and use those associated records. If we only want to aggregate the associated records somehow, includes
is wasteful, because all the associated records are pulled down into the app. For instance, if a User
has posts with many, many comments, we would pull down every single comment. This may be more rows than our Rails app can handle. And we don’t actually care about all
the individual rows, we just want the count of how many there are.
When we want to do an “aggregation” like summing the number of records (and don’t care about the individual records), we want to use joins
.
joins
# joins
can be surprising to SQL users. When we perform a SQL join, we expect to get “wider” rows (with the columns of both tables). But joins
does not automatically return a wider row; User.joins(:comments) still just returns a User. In this sense, joins
does the opposite of includes
. includes
fetches the entries and the associated entries both. User.joins(:comments)
returns no Comment
data, just the User
columns. For this reason, joins
is used less commonly than includes
.
What are the CRUD methods for Active Record?
Created, Update, Delete
- delete_all
- destroy
- destory_all
- create!
- update_attributes
What does this expression mean: Queries are lazy?
Querying methods like group, having, includes, joins, select and where return an object of type ActiveRecord::Relation. The Relation object looks a lot like an Array; like an Array you can iterate through it or index into it.
There is one major difference from an Array: the contents of Relation are not fetched until needed. This is called laziness. The Relation is not evaluated (a database query is not fired) until the results are needed.
What is ActiveRecord::Relation?
Querying methods like group, having, includes, joins, select and where return an object of type ActiveRecord::Relation. The Relation object looks a lot like an Array; like an Array you can iterate through it or index into it.
There is one major difference from an Array: the contents of Relation are not fetched until needed
How are query results cached by the Relation object?
After the query is run, the results are cached by Relation; they are stored for later re-use. Subsequent calls to each will not fire a query; they will instead use the prior result. This is an advantage because we can re-use the result without constantly hitting the database over-and-over.
This can sometimes result in unexpected behavior. First, note that when accessing a relation (e.g. user1.posts), a Relation object is returned. The relation is itself cached inside model object (e.g. user1) so that future invocations of the association will not hit the DB.
Caching results makes sense: it saves DB queries. But why is laziness a good thing?
Laziness allows us to build complex queries.
How do we force an associate to be reloaded?
caling variable.tablename(true)
How do we throw away all cached association relations?
variable.reload.
Why is laziness a good thing and how does it stack queries?
Caching results makes sense: it saves DB queries. But why is laziness a good thing?
Laziness allows us to build complex queries
georges = User.where('first_name = ?', 'George') georges.where_values # => ["first_name = 'George'"]
george_harrisons = georges.where('last_name = ?', 'Harrison') george_harrisons.where_values # => ["first_name = 'George'", "last_name = 'Harrison'"]
p george_harrisons
In this somewhat silly example, we call where twice. The first call to where returns a Relation which knows to filter by first_name (the condition is stored in the where_values attribute). Next, we call where on this Relation; this produces a new Relation object which will know to filter by both first_name and last_name (you can see that where_values was extended).
Note that the additional where created a new Relation; the original georges is not changed.
The first Relation returned by the first where is never evaluated. Instead, we build a second Relation from it. Here laziness helps us; it lets us build up a query by chaining query methods, none of which are executed until the chain is finished being built and evaluated.
Just like where has a where_values attribute, there are similar accessors for includes_values, joins_values, etc. You won’t ever access the attributes directly, but you can see how Relation builds up the query by storing each of the conditions. When the Relation needs to be evaluated, ActiveRecord looks at each of these values to build the SQL to execute.
How do we force an evaluation of a Relation
If you wish to force the evaluation of a Relation, you may call load. This will force evaluation if it hasn’t been done already. Using to_a will return an actual array.
Some other methods like count also force the evaluation of a query.