Giter Site home page Giter Site logo

active-record-models's Introduction

Building Models with ActiveRecord

Why is this important?

This workshop is important because:

ActiveRecord allows us to interact with a database by writing declarative Ruby instead of imperative SQL. It is a major component of Rails.

What are the objectives?

After this workshop, developers will be able to:

  • Create a model that inherits from ActiveRecord class
  • CRUD data in the database using our model
  • Write a migration to define a database schema
  • Update our database schema with another migration

Where should we be now?

Before this workshop, developers should already be able to:

  • Explain MVC
  • Write object oriented Ruby
  • Set and get data from a SQL database

##Models - Intro

MVC - Models

We can apply the design pattern of MVC to make more complex applications. Models literally "model" or describe the form of an object that we will represent in our application. This model object will contain methods that set and get its data in our database. Using a model, to a large extent, abstracts the complex SQL statements of a database away from the developer.

##ORM

So how does the model talk to the database?

Well, that's where ORMs come in. ORM stands for: Object Relational Mapping, and it's a technique that connects the rich objects of an application to tables in a relational database management system. Let's draw on the board how a user object, instantiated from the User class, could map to a Users table in our database.

####Example

Let's pretend we have a User class with the attributes id, name, age, and address:

class User
  attr_accessor :id, :name, :age, :address
end

And let's pretend that we create a new user, Rob Stark, whose object is shown below:

=> #<User:0x007fc8b18c5718 @address="1 Winterfell Lane", @age=16, @id=1, @name="Rob Stark", @king?=true>

With an ORM, we're able to take that instance of class User and map it to our relational database:

id |   name    | age |                      address                       | king?
----+-----------+-----+----------------------------------------------------+-------
  1 | Rob Stark |  16 | 1 Winterfell Lane                                  | true
(1 row)

Using ORMs, the properties and relationships of the objects in an application can be easily stored and retrieved from a database without writing SQL statements directly and with less database access code, overall.

##ActiveRecord

Rails Guides: Active Record Basics:

ActiveRecord, as an ORM Framework, gives us several mechanisms, the most important being the ability to:

  • 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

ActiveRecord is the Model in MVC. In other words it is the layer in the system responsible for representing business data and logic. We require it in our project by adding the gem activerecord

Preview

ActiveRecord methods will write the SQL for us, and once we've connected our database, we can pull any associated model data from it easily. Before we do that, let's set up our project to use ActiveRecord and configure which database we'll talk to:

Artist.all
Artist.create(params[:artist])
Artist.find(params[:id])

Including ActiveRecord

As noted earlier, ActiveRecord is a gem and since we're building an app with a bunch of gems using Bundler, take a look at the Gemfile and don't forget to bundle install!

Setting up the Database

####Setup

cd into starter-code and run bundle.

Note: ensure the version of ruby being run is at least ruby-2.2.2.

Database configuration

In config/database.yml, the name of the database is up to you, but <app_name>_development is a good pattern to get into. A typical application would have three databases, the other two being <app_name>_production and <app_name>_test for production and test environments respectively.

Makin' Models

Now that we're almost configured, let's make a class that uses all this fancy stuff. Under the models directory, note the file artist.rb.

class Artist < ActiveRecord::Base
end

Our new model will inherit all the code from the ActiveRecord class, which has a bunch of handy methods already on it. For example Artist.create will create a new Artist in the database or Artist.first will grab the first one in the database, etc.

This is where Rake comes in.

Rake technically stands for "ruby make", which is a tool we're going to use to run predefined tasks for us. You can program your own rake tasks, but ActiveRecord comes with a bunch of preset ones. We can use these to set up our Postgres database. By including active record in our Rakefile, we get access to it's built-in rake tasks.

Here's a pretty comprehensive list of rake commands you can run on the database.

$ rake -T

<List of rake commands here>

If we did this using SQL:

$ psql
psql (9.4.1, server 9.3.5)
Type "help" for help.

username=# create database tunr;
CREATE DATABASE

Instead, let's use a rake task.

Note: Before you do this make sure your Postgres application/server is open and running.

rake db:create

Boom, database created.

Migrations

Now that we have a database, we'll need to create some tables inside of it to store certain models we want to persist. Each table will have have columns that correspond to an attribute of one of our model instances.

"Migrations are a convenient way to alter your database schema over time in a consistent and easy way. They use a Ruby DSL [Domain Specific Language] so that you don't have to write SQL by hand, allowing your schema and changes to be database independent. You can think of each migration as being a new 'version' of the database." Source

Migrations are instructions to change the database's architecture. They can be automatically generated with active record. Migrations can always be rerun to recreate a consistent database state.

So let's build a new version of our database that has an artists table:

Note: we're using the gem standalone_migrations to do this as we're doing it outside a Rails project.

rake db:create_migration NAME=create_artists

A file is generated in db/migrate/. The string of numbers at the beginning is a Unix timestamp, while the remainder is what you just named it.

Now let's open the generated file and put the finishing touches on our table:

class CreateArtists < ActiveRecord::Migration
  def change
  end
end

Let's add some ruby code which will add columns to our table in order to allow for our model to have specific attributes. Let's say we want each artist to have a name, photo_url, and nationality.

class CreateArtists < ActiveRecord::Migration
  def change
    create_table :artists do |t|
      t.string :name #add a name attribute of type string to the table
      t.string :photo_url #also add a photo_url attribute of type string
      t.string :nationality # finally add a nationality attribute of type string
      t.timestamps #this will add timestamps for time created and time updated automagically!
    end
  end
end

Run the migration with rake db:migrate. That'll run any migrations that haven't been run yet and make the appropriate changes to the database.

== 20150710152405 CreateArtistsTable: migrating ===============================
== 20150710152405 CreateArtistsTable: migrated (0.0000s) ======================

###Sacred Cows

And we have a table! Nice work! And now you've got a schema.rb file that was generated for you—this file is sacred. Not to be touched, only to be admired. It's a snapshot of the current state of your database, and rake is the only one who should be modifying it, ever. Similarly, never change a migration file after it has been run. Repeat after me: "I shall never change a migration file after it has been run." Again! You can get a quick view of which files have been run by entering rake db:migrate:status. The files that have been run have a status of up, while those that have not have a status of down. Your file should have an up status now.

Peep your schema.rb to see what your database looks like!

ActiveRecord::Schema.define(version: 20150710152405) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "artists", force: :cascade do |t|
    t.string   "name"
    t.string   "photo_url"
    t.string   "nationality"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

end

Success, now let's change it again!

Changes to our DB - Demo

Just like we can write migrations to create tables, we can write migrations to add, change or delete attributes, update data types, change table names, and even delete tables. The entire purpose of migrations are to make architectural changes to the database.

We have also decided we want to collect data about the instruments the artists play, so we need to add a column to house that data. Let's create another migration:

rake db:create_migration NAME=add_instrument_to_artists
db/migrate/20150710154423_add_instrument_to_artists.rb

In the new migration:

class AddInstrumentToArtists < ActiveRecord::Migration
  def change
    add_column :artists, :instruments, :string
  end
end

You can probably guess what this line - add_column :artists, :instruments, :string—says: "add a column to the artists table called 'instruments' of type string". Run rake db:migrate:status to see two migration files, one up and one down. Once rake db:migrate is run, both will be down, and a new column will exist.

Make a migration every time a change to the database is needed—whether it's adding or removing something! Changing the database in any way means making a new migration, and telling the computer what you need done. Think of it as an assistant; you don't do the tedious Postgres work, you just tell it what needs doing and tell it to go do it. If you make changes in other ways to your local database, a team member who has cloned the same project will lose state with you. Running migrations of your other team members is how both of your separate local databases stay in state!

Changing or deleting column

By now, you've seen the pattern:

  • create a migration
  • add the appropriate code to the migration
  • run the migration.

Same pattern applies for each time you want to modify your database. For example in the case of a updating a column, you would write something along the lines of:

rake db:create_migration NAME=change_column_in_artists_to_new_column_name

Note the NAME doesn't matter, but it's a good idea to be descriptive.

In the migration add:

def change
  rename_column :table, :old_column_name, :new_column_name
end

Then:

rake db:migrate

According to the official ActiveRecord docs, these are all the migration methods that can be run inside change:

  • add_column
  • add_index
  • add_reference
  • add_timestamps
  • add_foreign_key
  • create_table
  • create_join_table
  • drop_table (must supply a block)
  • drop_join_table (must supply a block)
  • remove_timestamps
  • rename_column
  • rename_index
  • remove_reference
  • rename_table

As always, if you can't remember the exact syntax, reference the rails guides!

##Playing with our Data

Run app.rb to enter into a pry session.

###Creating

>> david_bowie = Artist.new
>> david_bowie.name = "David Bowie"
>> david_bowie.nationality = "British"
>> david_bowie.save

Here's .create, which does the same thing as .new and .save, but just in one step...

>> Artist.create({name: "Drake", nationality: "Canadian"})

Note: How does one see what SQL code has been generated by these commands?

###Reading

Now we can see how many artists we have Artist.count and see them all with Artist.all

###Updating

First we must find the artist to update and then change an attribute.

>> drake = Artist.find_by_name("Drake")
>> drake.nationality = "Canadian, aye!"
>> drake.save

###Deleting

We will now delete David Bowie, a moment of silence please...

It is best practice to use an id for finding an entry in the table. Assuming David Bowie is number 1 (which he is)...

>> david = Artist.find(1)
>> david.destroy

(´;︵;`)

###More CRUD actions

For a comprehensive set of all the CRUD actions ActiveRecord can perform checkout out the CRUD section of Active Record Basics on Ruby Guides!

Independent Practice

This a recommended pair programming activity.

In seperate migration files:

  1. Add a column "groupie"
  2. Rename the column "groupie" to "significant_other"
  3. Delete the column "significant_other"

Now, run the seeds.rb file with the command rake db:seed. Then, in app.rb write code to do the following:

  1. Find all artists
  2. Find the last artist
  3. Find the artist with the name "Enya"
  4. Find all artists who are American
  5. Create the artist "Puff Daddy"
  6. Change his name to "Diddy"
  7. Destroy "Diddy"

Closing Thoughts

  • What is ActiveRecord and how does it interact with your database?
  • What are migrations?
  • Why should you never touch schema.rb
  • Briefly, describe how to configure your Sinatra app to use ActiveRecord Models with your database.

Additional Resources

active-record-models's People

Contributors

ilias-t avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.