#WDI Week 4 Notes
##Monday
###Warmup
Bob:
https://gist.github.com/epoch/ea1798f7269f454f2445
My solution (exclusing the extension):
class Bob
def sure
puts "sure"
end
# if you ask him a question
def whatever
puts "whatever"
end
# if you tell him something
def chill
puts "woah, chill out!"
end
# if you yell at him
def fine
puts "fine, be that way!"
end
# if you address him without actually saying anything
def loser_speak
puts "loser speak"
end
#Start any sentence with "Bro, " and he'll translate the rest of it into l33t sP34k for you.
def chat(say)
if say.start_with?"Bro, "
loser_speak
elsif say.include? '?'
sure
elsif say.empty? || say == " "
fine
elsif say == say.upcase
chill
else
whatever
end
end
end
bob = Bob.new
bob.chat("Bro, ")
bob.chat("sup?")
bob.chat(" ")
bob.chat("")
bob.chat("SUP")
bob.chat("You're a fool")
###CRUD demos
Homework over the weekend was to create a CRUD system.
I made a blog, with no styling:
https://github.com/amysimmons/wdi8_homework/tree/master/amy/blog
###Patterns
Design Patterns: Elements of Reusable Object-Oriented Software (book)
###Rails appetiser
Movies example:
rails new movie_night
rails server
localhost:3000
rails generate scaffold movie title:string in_theatres:boolean released:date rating:string description:text
rake db:migrate (updating the database to include the movies table)
rails server
localhost:3000/movies
Intro example:
Rails has three different environments:
-
Development
-
Test
-
Production
We added the following gems to Gemfile...
group :development do
gem 'pry-rails'
gem 'pry-stack_explorer'
gem 'annotate'
gem 'quiet_assets'
gem 'better_errors'
gem 'binding_of_caller'
gem 'meta_request'
end
... then ran bundle in the terminal.
in routes.rb
Rails.application.routes.draw do
get '/home' => 'pages#home'
# if someone makes a get request to /home
# go and look in our pages controller and go and find the method called home
end
in pages_controller.rb
class PagesController < ApplicationController
def home
end
#we need a home method here because we have a page called /home
end
In views, we created a new folder called pages, which sits alongside layout. We then created a file in the pages folder called home.html.erb
Here's how Rails will work when we run the server:
-
When I bring up the rails server it will look into my routes.rb file to see what urls are available
-
If someone visits /home, rails will go to the pages controller to find the method
-
If Rails sees that there is no code in the method, it will then go and look for a view that matches the name of this method, so it will find the view called home.html.erb
Routes:
-
Runnign rake routes in the terminal will tell you how many urls are involved in the project
-
Or you can go to localhost:3000/rails/info/routes
-
We identify the root/home page by including in the routes.rb file
root :to => 'pages#home'
Debugging:
Rather than using binding.pry, use a raise like this:
class AutoController < ApplicationController
def color
raise "Something bad happen"
raise params.inspect
end
def engine
end
end
###Lab: Movie Stock
https://gist.github.com/wofockham/ae2479856769f8dbc804
##Tuesday
###Warmup
Decoding messages:
https://gist.github.com/epoch/21c0133143f03226cee0
My crappy solution, but it works!
message = "FRZDUGV GLH PDQB WLPHV EHIRUH WKHLU GHDWKV, WKH YDOLDQW QHYHU WDVWH RI GHDWK EXW RQFH."
message_arr = message.split(//)
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alphabet_arr = alphabet.split(//)
alphabet_shift = "DEFGHIJKLMNOPQRSTUVWXYZABC"
alphabet_shift_arr = alphabet_shift.split(//)
message_arr.each do |letter|
if letter != " "
index = alphabet_shift_arr.index(letter)
correct_letter = alphabet_arr[index]
print correct_letter
else
print " "
end
end
###Single Model CRUD - Planets
Create path '/'
Define our database
Create planets table
-
id integer autoincrement
-
name text
-
mass float
-
moons integer
-
distance integer
####The long SQL process
Step 1: Setting up the database
rails new solar_systems_app
Create planets.sql in db file
CREATE TABLE planets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
image TEXT,
orbit FLOAT,
diameter FLOAT,
distance FLOAT,
mass FLOAT,
moons INTEGER
);
Table name must be plural, the model itself must be singular
create the database by running rake db:create
it will create a file called development sqlite 3
we can then cd into the db folder
run sqlite3 development.sqlite3 < planets.sql in the terminal
this pushes the planets table into the database
to test that it worked run sqlite3 development.sqlite3 .schema and it should return the table structure
Step 2: Creating a model
Now we need to create a model to make this work
The model goes in the app folder, in a folder called models
create new file planet.rb
into that file put
class Planet < ActiveRecord::Base
end
gem install annotate
run annotate
this inserts a big comment into my planet.rb file which shows the table name and characteristics
An alternative to pry:
in order to deal with pry we can type rails console in the terminal
then we can start running commands like Planet.all
In order to be in pry rather than console,
put these into my gemfile
group :development do
gem 'pry-rails'
gem 'pry-stack_explorer'
gem 'annotate'
gem 'quiet_assets'
gem 'better_errors'
gem 'binding_of_caller'
gem 'meta_request'
end
then run bundle
then run rails console again
you could do earth = Planet.new
and then set all the properties
or you can do this
venus = Planet.create :name => 'Venus', :mass => 3, :diameter => 11, :distance => 1, :moons => 2
Planet.destroy_all will destory all planets
Planet.count should now show zero
Step 3: Seed data
The seeds.rb file is for seed data
Planet.create(:name => 'Earth', :orbit => 1, :moons => 1)
Planet.create(:name => 'Mars', :orbit => 1.5, :moons => 2)
Planet.create(:name => 'Venus', :orbit => 0.7, :moons => 0)
Planet.create(:name => 'Jupiter', :orbit => 3.7, :moons => 7)
Planet.create(:name => 'Pluto', :orbit => 5, :moons => 3)
Enter some seed data and then run rake db:seed in terminal
This connects the seed data with the database
to test that it worked, in the console, run Planet.count / Planet.all and the seed data should be there
if you make a mistake while playing around with your data, you can restore the original seeded data by reseeding them
first you need to add Planet.destroy_all to the top of the seeds.rb file
then when you re-run rake db:seed it will first destroy all existing planets, then reseed the original ones
rake db:drop (deletes the database)
delete sql file
so all that's in db folder is the seeds file
####Rails generating the migration for us, without us having to write SQL
in solar_system_app run
rails generate migration create_planets
the rb file should appear in the migrate folder
it tells rails to create a table
so this is the equivalent of our sql stuff, but its a lot more rubyish
class CreatePlanets < ActiveRecord::Migration
def change
create_table :planets do |t|
end
end
end
so we want to insert into the do block our table details
class CreatePlanets < ActiveRecord::Migration
def change
create_table :planets do |t|
t.string :name
t.text :image
t.float :orbit
t.float :mass
t.float :diameter
t.float :distance
t.integer :moons
t.timestamps
end
end
end
this table works across all databases now
rake db:create (creates the db)
rake db:migrate (finds any unapplied migrations and performs them)
at this point you can run annotate, then go back to the planet.rb file to check thar the table is there
at this stage we have set up the M part of our MVC model, but we haven't set up any routes
Setting up the routes:
in the routes.rb file
get '/planets' => 'planets#index'
in terminal run rails generate controller planets index
this means rails will create the file for me and create the views folder and put an index.html.erb file in there ready for me to customize
rake db:seed
rails console
Planet.all
Recap of the above steps:
rails new something -T
cd something
rails generate migration create_whatever
subl . #fill in the migration
rake db:create
rake db:migrate
touch app/models/whatever.rb
annotate
rake db:seed
http://localhost:3000/info/routes
will show you the urls and the methods to get to those urls
we changed the new planet form so that all the name values were formatted like this - planet[moons]
this is so we can view the planets better in the controller
>> params
=> {"name"=>"", "planet"=>{"image"=>"", "orbit"=>"", "mass"=>"", "diameter"=>"", "distance"=>"", "moons"=>""}, "controller"=>"planets", "action"=>"create"}
>> params[planet]
!! #<NameError: undefined local variable or method `planet' for #<PlanetsController:0x007fc52bedecc8>>
>> params["planet"]
=> {"image"=>"", "orbit"=>"", "mass"=>"", "diameter"=>"", "distance"=>"", "moons"=>""}
>> params["planet"]["name"]
=> nil
>> params["planet"].keys
=> ["image", "orbit", "mass", "diameter", "distance", "moons"]
>>
###Lab: Single Model CRUD - Oceans or Mountains
###Reading: Active Record Helpers
http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-image_tag
###Reading: Active Record Migrations
http://guides.rubyonrails.org/active_record_migrations.html
You can think of each migration as being a new 'version' of the database. A schema starts off with nothing in it, and each migration modifies it to add or remove tables, columns, or entries. Active Record knows how to update your schema along this timeline, bringing it from whatever point it is in the history to the latest version.
##Wednesday
http://postgresapp.com/ - a fancier version of sqlite3
###Art Gallery code along
Thinking through the tables:
We are going to have two tables - Artists and Works
One artist can have many works.
An artist will have:
- name (string)
- nationality (string)
- dob (date)
- period (string)
- image (text)
An artwork will have:
- title (string)
- year (string)
- medium (string)
- style (string)
- image (text)
- artist_id (int) *this is the association
the above layout assumes only one artist has worked on an artwork.
if you needed to have multiple artistis on one work, then you could have a third table, a join table, that just stores the ids.
it would be called artist works, with two columns, an artistid column, and a work id column.
Setting up the rails app:
rails new moma -d postgresql -T
the above won't include the sqlite gem in gemfile and will use the pg gem instead. it's telling rails which database system to use.
-t tells rails not to include any development files
add the following gems to gemfile and run bundle
group :development do
gem 'pry-rails'
gem 'pry-stack_explorer'
gem 'annotate'
gem 'quiet_assets'
gem 'better_errors'
gem 'binding_of_caller'
gem 'meta_request'
end
config database.yml file, need to make some changes to the development group
we need to specify the host and username
host: localhost
username: amysimmons
these go under the line that says database: moma_development
then we deleted everything below those lines
run rake db:create to create the database
Creating the first table:
rails generate migration create_artists
this tells it to make an artists table in the database folder, which needs to be plural, because the table will store many artists
go and add your table elements in your migrate folder
class CreateArtists < ActiveRecord::Migration
def change
create_table :artists do |t|
t.string :name
t.string :nationality
t.date :dob
t.string :period
t.text :image
t.timestamps
end
end
end
then run rake db:migrate
check your schema.rb file and the table should be there
next step is to create my model
touch app/models/artist.rb
in the artist.rb file add
class Artist < ActiveRecord::Base
end
now we need to make sure the Artist class needs to be able to find the table that is associated with it
the easiest way to test it is to run annotate
then go check the artist.rb file in models folder to check that the annotation comments are there
all annotate does is add the comment at the top of that file
Creating the second table:
rails generate migration create_works
in the migrate folder add the table elements
class CreateWorks < ActiveRecord::Migration
def change
create_table :works do |t|
t.string :title
t.string :year
t.string :medium
t.string :style
t.text :image
t.timestamps
end
end
end
repeat above steps to set up the model and make sure the class is connected with the new table.
Adding seed data:
Added the following to the seeds.rb file
Artist.destroy_all
Work.destroy_all
Artist.create(:name => 'Joan Miro', :nationality => 'Spanish', :dob => '1893/04/20', :period => '20th century', :image => 'http://upload.wikimedia.org/wikipedia/commons/5/5c/Portrait_of_Joan_Miro%2C_Barcelona_1935_June_13.jpg')
Work.create(:title => 'The Flight of the Dragonfly in Front of the Sun', :year => '1968', :medium => 'oil on canvas', :style => 'Abstract Art', :image => 'http://uploads0.wikipaintings.org/images/joan-miro/the-flight-of-the-dragonfly-in-front-of-the-sun.jpg')
rake db:seed to run the seed file
rails console
Artist.all should get me all artists
Work.all should get me all works
Start building the routes:
in the routes file you can say i want you to create resources for artisists, it writes all those routes for you
Rails.application.routes.draw do
resources :artists
end
resources :artists resources :works
this creates the same seven set of routes that we have been working with previously. AMAZE!!
What if I make a mistake in my table?
rake db:rollback undoes the most recent migration
fix the code
then run rake db:migrate again
then annotate again and check that it's been fixed
###Associations
###Lab: Books and Authors
##Thursday
##Friday