Database Migrations

Summarized using AI

Rails for Zombies: Parts 1 & 2

Christopher Greene and Aimee Simone • June 25, 2013 • Portland, OR

The video "Rails for Zombies: Parts 1 & 2" featuring Christopher Greene and Aimee Simone breaks down fundamental concepts of Ruby on Rails through a fun, interactive workshop tied to a thematic project called "Twitter for Zombies." The session is designed for both beginners and more experienced developers looking to refresh their Rails skills.

Key points covered include:

- Getting Started with CRUD: The workshop kicks off with an explanation of CRUD (Create, Read, Update, Delete) operations, fundamental to web applications. The presenters illustrate CRUD by using examples related to a zombie-themed application.

- Database Structure: Participants learn about database tables and structures, initially focusing on a 'tweets' table and how to retrieve specific data from it. The presenters detail how to query the database using Rails conventions, like using tweet.find(3) to get tweet details.

- Creating New Records: The video discusses the process of creating new entries in the database, using tweet.new and T.save, as well as alternative one-liner commands like tweet.create.

- Reading and Updating Data: The tutorial elaborates on various methods to read from the database, such as find, where, and their efficiency in counting records without pulling all data. Additionally, updating methods are explained, including modifying attributes and saving changes efficiently.

- Database Migrations: Greene and Simone dive into the concept of database migrations, emphasizing their importance in version control of the database schema. They walk through the generation of migration commands and the execution of rake db:migrate to implement changes.

- Using the Console: The presenters showcase how to use the Rails console for testing and debugging, highlighting examples of commands for creating and retrieving zombies, and how to change the zombie's attributes safely.

- Hash Syntax in Ruby: The difference between older and newer hash syntaxes in Ruby, particularly focusing on Ruby 1.9 syntax, is addressed.

- Rake Tasks: Greene explains various rake commands that help manage database tasks, such as rake db:rollback for undoing migrations and how to quickly set up the application using the schema file.

- Configuring the Database: The configuration of the default SQLite database is discussed, along with how to switch to MySQL if required.

Overall, the workshop encourages viewers to actively participate by coding along in a fun environment, establishing foundational skills in Ruby on Rails while nurturing creativity in application programming. The session concludes with a call to action for participants to engage deeply with the presented material through hands-on experience.

Rails for Zombies: Parts 1 & 2
Christopher Greene and Aimee Simone • June 25, 2013 • Portland, OR

Workshop with Christopher Greene & Aimee Simone

RailsConf 2013

00:00:16.070 In order for this video to make sense, you're going to need to know a little bit about the Ruby language. If you don't know anything yet, pause this video, go to tryruby.org, go through that tutorial, and then come back to start the video. So in this first episode, we're going to be diving into CRUD; we're going to be talking about CRUD. Now bear with me if you're an expert in some of these languages and concepts; we'll get to the advanced stuff soon enough, but we need to make sure everyone's on the same page.
00:00:33.920 We're going to be creating Twitter for Zombies— that's our application. If you don't know why, go back to the front page and watch the intro, but let's jump into it for now. Here we have our first database table. It looks kind of like a spreadsheet— we're calling it 'tweets.' It has four rows and three columns.
00:00:51.860 Now we might put a label on each of these columns. The first one is the ID, the second one is status, and the third one represents the zombies, like Ash, Bob, and Jim. These are our zombies. Our first zombie challenge is going to be to retrieve a hash of the tweet with ID equal to three. I'm not going to show you the solution just yet; first, I want to show you the result we want to get back from the database.
00:01:10.840 In this case, we want to get back a hash that looks like this. You should be familiar with what a hash is, but here's a small recap. If we do puts B status, we're going to get back 'I just ate some delicious brains.' If we do puts B zombie, we're going to get back Jim. And if we do this at the bottom, we'll see 'Jim said I ate some delicious brains' because you know zombies love eating brains.
00:01:35.720 Now let's get back to our database table and our challenge. So there's our challenge again. Now I'm going to show you the actual solution— the code that we want to write. We want to write T equals tweet dot find three. What that's going to do is get us back that hash. We can then do put CID to get us three, puts T status to get 'I just ate some delicious brains,' and puts T zombie gets us back Jim.
00:01:55.730 Now there's another way we can write this in Rails. Instead of puts T ID, we can do put T dot ID, puts T dot status, and so on and so forth. We can use these to find our solution instead of using the hash keys. Here's what our answer might look like with those pieces of code.
00:02:11.060 There's one Rails convention here that I want you to notice. Notice we have a capital 'T' in 'tweets' in the code solution, and what's happening on the back end is that it's going to lowercase that, pluralize it, and then look for a table called 'tweets' in our database.
00:02:33.990 It's time to jump into the CRUD— by CRUD I mean create, read, update, and delete. Now let’s figure out how we can do each of these inside our Rails application. First, in create, we do tweet.new, set the status, and call T.save to save the item. For reading, we then do tweet dot find three just like you saw a moment ago. For updating, we're going to find the tweet, set values on it, and save it. Then for delete, we can find the tweet and call T dot destroy to delete it from the database.
00:02:53.880 Now we're going to go through each of these in a little bit more detail, and I'm going to show you some alternate syntaxes. But first, with create, notice that we're not setting the ID on the object here. That's because Rails is going to take care of that for us and properly increment the ID and store that in the database.
00:03:04.370 Another way we can create a new tweet is simply by sending in a hash of the items that we want to set. We can then save that. We can also write this all in one line by calling tweet.create, which will set these attributes and save the object.
00:03:20.620 Next up for reading, there are lots of ways we can read data out of the database. We can find a particular item with an ID number, find a bunch of items which will return an array, find the first one, find the last one, or find all of them. We can count them, and the interesting thing about count here is that it does it the correct way. It's not going to the database, pulling everything out, and then counting it; it actually does a count query on the database and returns that number.
00:03:43.510 We can also get all the zombies and order them by zombie name, limit the number to ten, get all zombies where the zombie name equals Ash, or we can put all these different methods together to do something we like to call method chaining.
00:04:01.890 Next up we have update. Remember with update we find the tweet, set something, and then save it. Alternatively, we can set the attributes values and send it in a hash and then save it. We can also call T dot update attributes, which will not only set the items but also save it. Next up is destroy, because zombies like destroying things, especially brains. So as you saw before, we can find an item and destroy it. We can also write this on a single line, and lastly, if you want to destroy all the tweets, we can just call tweet dot destroy all.
00:04:40.510 So we've already reached Zombie Lab 1. This is where you get to start coding and implement some of the stuff we've already learned. So go and have fun with your new zombie friends.
00:05:14.620 Welcome to Rails for Zombies - level 1. In this episode, we're going to go over some of the things we left out in the first set of Rails for Zombies videos covering topics like creating a Rails app, the command line, database migrations, the Ruby 1.9 of Bundler, and database configuration.
00:05:19.400 If you haven't yet, I highly recommend you get Rails installed on your laptop or computer so that you can run some commands and follow along as we teach them. I’m not going to go into the nitty-gritty details of installing Rails on every platform; I'm just going to mention that if you're on Windows and don’t have it installed yet, head over to railsinstall.org. There are instructions there, a downloader, and you'll be up and running in no time.
00:05:38.510 If, however, you're running OS X or Linux, I highly recommend going over to railstutorial.org and just going through the first chapter. It'll get everything installed for you, and you'll even get an application deployed on Heroku. Once you have Rails installed, if you run 'rails' from any directory that's not a Rails app, it's going to give you the syntax on how to create any Rails app with a bunch of different options— you can skip active record, specify what database you want to use, specify what JavaScript framework you want to use, couple runtime options, and finally, it'll give you an example of how to create the Rails app.
00:06:05.680 Let's go ahead and create our first Rails app by running 'rails new Twitter for Zombies.' When we run that command, it's going to create a bunch of files and directories for us. Some of these directories should look familiar from Rails for Zombies 1, like your controllers, models, and views directory.
00:06:26.280 At the end, it's going to run 'bundle install.' What 'bundle install' does is go out to the internet and download any external dependencies that your Rails application depends on. You don't need to worry about this too much; we’ll come back around and talk about Bundler later. So we've created our Rails app; now let's jump into the directory. We’re going to 'CD' into the directory, and if we run 'rails' from inside the directory, we're going to be given a list of commands that we can run on a Rails app.
00:06:49.560 This starts with the generate command, which generates new code, the console command which we’ll use to debug a little bit later, the server command to start our local development server, and the DB console command to jump into a console for our database. If we want more information about any of these commands, we can run them with the '-h' option. But first things first, let’s get our development server running, so we're going to run 'rails server.' That's going to give us some output and if we go to localhost:3000 in a browser, we're going to get the 'Welcome to Rails' screen.
00:07:15.300 We can also run 'rails server -h' for more options like running the server on a different port. The shortcut for this command, which we’ll probably run more often, is just 'rails s.' Next up, let's take a closer look at the 'rails generate' command. If we run it without any options, we're given a list of generators which we can use to generate some source for our Rails app. The shortcut for generate is 'rails g' and let's go ahead and use that to generate a scaffold.
00:07:36.470 A scaffold, if you're not familiar, is the basic building block for most of our Rails apps. We specify a resource, and it builds us a view to list out the items, edit the items, create new items, and delete the items. Here’s the syntax: we're going to go ahead and create 'rails g scaffold zombie' because we want to create zombies. We're going to give it a name which is a string, a bio which is a text type, and an age which is an integer.
00:08:05.700 When I say types, I'm referring to database types, and here's a list of all the other database types which we might find useful. When we generate a scaffold, it's going to create a bunch of files for us. Let’s take a look at a few: You can see here it’s generating a migration for us, the zombie model, it’s going to add resources 'zamba' to our routes.rb, it's going to create our zombies controller, and it’s also going to create our views which should look familiar from Rails for Zombies 1; you have our index view, edit, show, and new.
00:08:30.630 There are a couple other files that it's going to create, like helpers, tests, and assets, and we’ll see some of those later. But first, let's jump in and take a closer look at that migration. When we say migration, we're talking about our database migrations. This is how we make changes to our database from inside Rails. If you remember from Rails for Zombies 1, Rails is going to automatically create for us a primary key called ID; it doesn't even show that in the migration.
00:08:51.620 It's just assumed that every table is going to have a primary key of ID. The last thing you’ll see in this migration is this T.timestamps line. This T.timestamps line is the same as saying date/time created_at and date/time updated_at. These are magical fields in Rails—they get populated for you automatically, and you can use them in your views. When a model is created, the created_at gets set, and every time it’s updated, the updated gets set for you.
00:09:21.280 To give you a better idea of why migrations are so useful, here's a commercial I created back in my Rails Envy days. Hi, I'm Ruby on Rails. What you got there? Oh, these are a bunch of SQL files that all the developers on the team set out, and I’m really frustrated because they just keep overriding my database changes. It sucks.
00:09:52.460 Yeah, you feel my pain, right? Well, actually, Ruby on Rails uses something called migrations. This allows developers to make database changes independently without stepping on anybody's toes. You still have to write tons of SQL though, right? Well, no. Migrations actually use Ruby, so it’s database independent.
00:10:22.940 Wow, that sounds really good. I think I’ll give that a try! Actually, you know what, on my way home from work tonight, I’ll stop by Toys R Us and pick one of those up. While I’m there, I’ll get Barbie to give me a ride in her pink Cadillac all the way to your office in the land of make-believe where you can help us finish up my application and we’ll all live happily ever after.
00:10:49.440 So database migrations are how we version our database and keep track of changes, so we don’t have to send around SQL scripts and end up stepping on each other's toes. So back in our Rails app, we have this migration. If we start up the server at this point, uh-oh, we're going to get an error; it's not going to work. It gives us an error and shows us the line of code where there's an error. If we looked at that line of code, we would see zombies equal Zombie.all.
00:11:12.490 So it’s looking for the zombies table, but it's not yet in the database. Ah, we forgot to run that migration file! To run migration files, we run 'rake db:migrate.' Not only is that going to run our current migration, but if there are any other migrations that other people in our project committed, it’s also going to run all of those. Here’s the output we would see from our migration, and if we run our Rails server again now, if we go to '/zombies', we can get a list of the zombies and start creating them.
00:11:43.290 Now that we have a zombie table and a zombie model, let's jump into the console and play around with it. We use the console to debug our application so we can go in here and just start running Rails commands. Here, you can see I’m running Zombie.create with name 'Eric', alive, and age 27. That’s going to actually show us the SQL that’s going to be running inside of our Rails app, and it’s going to give us back the zombie object it created.
00:12:02.790 Now remember when you use tryruby.org, everything in Ruby has a return value— that's that hash rocket symbol you see right up there. You can see that this command returns an instance of the zombie. We can then run Zombie.first to get back the first zombie, which in this case is the zombie we just created. We can change the name of the zombie, and then finally, we can save the zombie, which is going to show us the SQL that it uses to do that, and it’s going to return true because it’s successfully saved the zombie.
00:12:25.740 Now you may have noticed that when we created this zombie, Eric here, we used a slightly different syntax. We actually used a different hash syntax. Remember, a hash is a collection of key-value pairs, and a key can be almost anything. A key can be a string. Here’s the old syntax with a hash rocket; the key can be a number; a key can more commonly be a symbol. You'll notice all of these different syntaxes I showed you here are compatible with both Ruby 1.8 and 1.9.
00:12:56.780 If we're using Ruby 1.9, this last hash can also be written as name:— it’s a little bit of a shorter syntax with two less characters. Throughout this entire tutorial, we're going to be using this new Ruby 1.9 syntax. If you're just getting into Rails now, you should be using Ruby 1.9— don’t even bother with 1.8; just use Ruby 1.9 and then you'll get access to this hash syntax you see here as well.
00:13:19.390 So here again is the code to create zombie Eric using the Ruby 1.9 syntax, and here it is using the Ruby 1.8 syntax. But really, it’s not Ruby 1.8 syntax; you can still use the same syntax. This is sort of old hash syntax in either Ruby 1.8 or 1.9. It's up to you which one you like better; you can use either. But in this tutorial, like I said, we’re going to use the new way.
00:13:40.350 If you take a look inside the controller that the scaffolding created for us, you can see that in the respond_to block over here, it says render :json, @zombies. That's using the Ruby 1.9 syntax, and it does the same thing as the old syntax. We have our zombie table, but we want to make some changes to the database. How do we do that? Well, we do that by generating a migration.
00:14:00.130 We're going to call our migration 'add_email_and_rotting_to_zombies.' We're going to specify the columns we want to add: in this case, the email column, which is a string, and rotting, which is a boolean. When we want to add a migration that adds columns, we can use this title format, and it'll write all the code for us. So we say 'add anything to' and then the table name. We have our column names and types, and that's going to generate a migration for us that looks a little bit like this.
00:14:25.490 As you can see here, it’s adding two columns to our zombies table: an email column and a rotting column. But what happens when we want to add some table options—some column options for a default? We can just write 'default: false.' A couple of other migration options here, besides default, are: we can also add a limit, specify whether it can’t be null, specify position in the table to put the column, as well as add a unique constraint to ensure that this column is always unique at the database level.
00:14:56.000 Now that we have a migration, we need to run 'rake db:migrate' to add those columns to our database. 'Rake db:migrate' is not only going to run our new migration, but if I checked out somebody else's migrations, it's going to run those too. Some other rake commands you need to be familiar with start with 'rake db:rollback.' What 'rake db:rollback' is going to do is look at our most recent migration and undo it at the database level. It’s going to roll it back.
00:15:13.390 This can be really useful if, let’s say, I haven't committed my migration yet and I want to make some changes and then migrate again. It's also really useful when you think about deployment. If I deploy my application, run the migration, and, oops, I didn’t want to run that—something went wrong—I can quickly type 'rake db:rollback.' That will roll back the migration, and I can make any changes that I need to from there.
00:15:35.860 Another useful rake command is 'rake db:schema:dump.' This gets run automatically every time we run 'rake db:migrate.' See, after you have a Rails app that’s lived for three or four years, you can end up with a lot of migrations. I mean, over a hundred migrations, and it's unrealistic for a new developer to have to run all those migrations. What you find is that migrations start to get brittle after a while. This is why we have a schema.rb.
00:16:04.900 It looks something like this: as you can see here, it has our entire database structure. So the next time you check out somebody's Rails app and you need to get up and running and create the database, what you're going to run is 'rake db:setup.' That’s going to create the database if it doesn’t exist yet, run the schema, and create the database using that schema file, and then it’s going to run any seed data you need in there.
00:16:24.680 So we know how to add columns to our database, but how do we remove them? Well, let’s go ahead and generate another migration for that. We’ll call it 'remove_age_from_zombies.' The column we want to remove is the age column, which is an integer, and we are using another pattern here with the migration name 'remove something from table name.' That’s going to generate a migration for us. It’s obviously going to have the 'remove column' command, but if you look at that 'remove column' command, you’ll notice it doesn’t have enough information in it to roll it back.
00:16:50.810 Sure, we can remove the column, but when we want to add it back, what type was it? So in this case, we also need to have an 'add column' command in here. Now, remember, in the previous migrations, we had a change method. Instead of a change method, we're going to have an up method to migrate up and a down method so that our application knows what to do if we need to roll this migration back.
00:17:12.240 A couple of the migration commands include 'rename column', 'rename table', 'drop table', 'change column,' and 'change column default.' So we know how to add columns, we know how to remove columns, but what about everything else? Well, for everything else, we're simply going to create a migration and name it anything we want. So in this case, let's drop the zombies table altogether.
00:17:42.400 That's going to generate a up-and-down method for us, and we’re going to have to write it. You can see here I’ve written it for us; we have a drop table in the up and we have a create table in the down. For more information on database migrations, head over to guides.rubyonrails.org— there’s a Rails database migrations guide which has tons of great information about migrations.
00:18:01.720 So when we created our Rails app, it ran 'bundle install' and installed external dependencies. How do we know which dependencies to install? Well, that came from the Gemfile which is at the root of our directory. Here you can see a listing of all of our Rails app's external dependencies, and whenever we want to make sure we have these installed or go out and install new ones, we can just run 'bundle install.'
00:18:25.720 And remember I got called by default when we created our first Rails app. For more information on Bundler, obviously, I don’t have time to go into all the nitty-gritty. Head over to rubyonrails.org in the screencast section; there you’ll find a screencast on bundler I created. Also, you can go straight over to the bundler website at gem bundler.com.
00:18:52.280 By default, our Rails application uses a SQLite database. One way we can tell this is on the previous slide where we saw our gem dependencies; it had listed 'gem sqlite3' so it's using a SQLite database. But how is our database configured? Well, that happens in our config database.yml. Let’s take a look inside.
00:19:11.350 Here you can see we have a configuration for our development, test, and production environments. How might we change this out for MySQL? We simply would have to change this configuration, giving it the MySQL adapter, the database name, the username, and password for our database, and we would replace the SQLite driver with MySQL inside of our Gemfile, run 'bundle install,' and then we’d be using MySQL.
00:19:46.740 That’s all we're covering for level one. Now it's your turn to take this information and learn by doing in the challenges.
Explore all talks recorded at RailsConf 2013
+93