Code Academy Week 11 Notes

2012-03-20_08.52.33
Look at rspec
to not include default testing framework:

rails new AppName -T

In Gemfile:

gem 'rspec-rails'
ericm@finance:~/ruby/MeatdownApp$ rails g rspec:install
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
rails g model User name:string
      invoke  active_record
      create    db/migrate/20120320135609_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
ericm@finance:~/ruby/MeatdownApp$ rake db:test:prepare

to update test database

History for rails and rspec project:

2005  rails new MeatdownApp -T
 2006  cd MeatdownApp/
 2007  bundle install
 2008  rails g rspec:install
 2009  rails g model User name:string
 2010  rake db:migrate
 2011  rspec spec/models/
 2012  bundle install
 2013  rspec
 2014  rake db:test:prepare
 2015  rspec
 2016  gem list --local
 2017  bundle install
 2018  rspec
 2019  bundle install
 2020  rspec
 2021  bundle exec install
 2022  bundle exec
 2023  ruby -v
 2024  rails g model Meetup title:string
 2025  rake db:migrate
 2026  rake db:test:prepare
 2027  cp -v /home/ericm/github/digital_schoolhouse/.rvmrc .
 2028  emacsnw .rvmrc
 2029  cd ../
 2030  cd MeatdownApp/
 2031  bundle install
 2032  rspec
 2033  rails g migration AddUserIdToMeetup user_id:integer
 2034  rake db:migrate
 2035  more db/schema.rb
 2036  rake db:test:prepare
 2037  rake
 2038  rspec
 2039  history

 

Dave Hoover
He had to create his own software engineering education
His advice:
1. seek out mentors
2. kindred spirits
3. Community

He tries to be the worst person on the team
Keep diving deeper into Rails, know about testing
he uses TestUnit – no RSpec back then
Expand your bandwidth, drink from the firehose
Learning is fun, but debugging may not be
Learn how to expand/contract your bandwidth
After Code Academy: Don’t be discouraged
Very few people just walk right into a job
It takes some time
Reach out, ask people in the community, find out what is out there
Apprentice: 8th Light, Groupon, Trunk Club
You will need to hustle

——
.rspec file:

--format nested
--color

We want a model without a database table

rails g model CoinChanger --no-migration

No migration generated, but it still has ActiveRecord in it

class CoinChanger < ActiveRecord::Base
end

so take out “< ActiveRecord::Base”

If you just run “rake”, it will run your tests
Jeff do not test your views, just your models and controllers

2012-03-22_08.30.05
Modules: you can include or extend a module
you can extend a module and use its methods as class methods by calling with “extend”
in irb: you can require or include files

require "./modules"

if it is in same dir from which you called irb
You could also “load” a file

load "modules.rb"

This will reload the file if you call it again
in the file you can call “require relative ‘modules'” which goes from pwd of the file
Modules extend a class that extends Kernel

It is better to use composition than inheritance many times
inheritance cements the relationships. It only works for one kind of re-use: is-a

In modules you can make a method self.method_name and you can make those available at module level
No instance needed

self keyword: it refers to the current object
class scoped code is executed when code is read/loaded/class initialized
It is only run once

class Table
end
puts self

That second self will print “main” even though you are not in a class, “out in hyperspace” as Jeff puts it

In class scope, self returns name of table, inside an instance method, self refers to the instance

— look for a “collect” method

We could make a method called “method_missing” that will handle any calls to undefined methods

def method_missing(m, *args )
end

m is a symbol that is the name of the ghost method
*args is an array of args

def method_missing(m, *args )
  puts "whoa! you tried to call #{m.to_s}, with these args:"
  puts args.inspect
end

This may be how Rails does find_by_column name:
it uses regular expressions in method_missing

You could also call super in method_missing

Another use of modules: namespacing

module Jeff
  class Boat
  end
end
b1 = Jeff::Boat.new
b2 = John::Boat.new

If you have two classes with the same name, you will get the union of the classes
If the same method name is used, the last method defined wins

You could add to String, Array, Hash

modules package stuff for re-use and good for namespacing

You can call instance.respond_to?(length) to see if it will respond to that method call

s = "Hello"
s.respond_to?(:length)
s.send(:length)

You may get stuff in a variable

gem list acti

will give the gems with “acti” in the name

gem which will_paginate

will tell you where the gem was installed

gem list -d activesupport

In rails apps, there is a lib/tasks directory
Make a file called flights.rake

it must go in a block

task :jeff do
  puts "hi"
end

Then you can call “rake jeff”
To see in the list, put
desc “sample rake task”
in the file – before line with :task

task :prereq do
end

task :jeff => :prereq do
end

This will make the :jeff task run the :prereq task first

What if you deal with models?

task :list => :environment do
  puts "We have #{Airport.count} airports"  
end

You can namespace your tasks

namespace :air do
  task :jeff do
  end
end

Image from World Digital Library, assumed allowed under Fair Use. Image from the Psalter of Frederick II, a 13th century manuscript in the Byzantine style, housed at Riccardiana Library of Florence, aka Biblioteca Riccardiana.

Code Academy Week 10 Notes

2012-03-13_08.54.13
Hidden field in a form: f.hidden_field(:list_id)

Nested resources:

resources :students
resources :grades

But is a top-level list of grades any good?

Do this in routes.rb

resources :students do
  resources :grades
end

students/1
students/1/grades
students/1/grades/4
1 is :student_id, 4 is :id for grade

Coffeescript:
coffeescript.org
It is the default syntax for Rails 3.1 and up

$(function() {
  $("#aha_learned_on").dateicker();

becomes

$ ->
  $("#aha_learned_on").datepicker()

For code block, you indent instead of using braces. Indentation is meaningful. So use soft tabs.
We need parentheses if the function takes 0 parameters.

$("#new_item_link").click (e)->
  $("#new_aha").fadeIn()
  $("#new_item_link").hide()
  e.preventDefault()

HAML:
Put in two gems:

gem 'haml'
gem 'haml-rails'
gem 'haml-rails', :group => :development

 

rails generate scaffold landmark name:string rating:integer

So we get haml:

ericm@finance:~/ruby/codeAcademy/week10/LandmarksApp$ rails generate scaffold landmark name:string rating:integer
      invoke  active_record
      create    db/migrate/20120313152347_create_landmarks.rb
      create    app/models/landmark.rb
      invoke    test_unit
      create      test/unit/landmark_test.rb
      create      test/fixtures/landmarks.yml
       route  resources :landmarks
      invoke  scaffold_controller
      create    app/controllers/landmarks_controller.rb
      invoke    haml
      create      app/views/landmarks
      create      app/views/landmarks/index.html.haml
      create      app/views/landmarks/edit.html.haml
      create      app/views/landmarks/show.html.haml
      create      app/views/landmarks/new.html.haml
      create      app/views/landmarks/_form.html.haml
      invoke    test_unit
      create      test/functional/landmarks_controller_test.rb
      invoke    helper
      create      app/helpers/landmarks_helper.rb
      invoke      test_unit
      create        test/unit/helpers/landmarks_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/landmarks.js.coffee
      invoke    scss
      create      app/assets/stylesheets/landmarks.css.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.css.scss
ericm@finance:~/ruby/codeAcademy/week10/LandmarksApp$

In HAML, whitespace is significant
For classes for p tag, you could do this:
p.red.something

Back from break
If you have a list of items with an association:

has_many :items

you can use :dependent with :delete, :delete_all will delete without calling callbacks (like if you have some email actions), :nullify removes foreign key

has_many :items, :dependent => :destroy

Use twitter authentication
Create a sessions controller

rails g controller sessions new create

The create action will be called by Twitter

class SessionsController < ApplicationsController
  def create
    logger.debug "hello"
    # logger.debug request.env['omniauth.auth'].inspect
    auth_data = request.env['omniauth.auth']
    logger.debug "Provider: #{auth_data['Provider']}"
  end
end

Routes:

get "sessions/create"

Use the omniauth gem
This gem will add routes to your application.
1. Register your app with twitter at https://dev.twitter.com
You get Access Level, Consumer Key, Consumer Secret, Request Token URL, Authorize URL, Access Token URL, Callback URL
We set the callback URL
You need to put in 127.0.0.1 instead of localhost for dev
2. In gem file
You need to add a gem for each “strategy” https://github.com/intridea/omniauth/wiki/List-of-Strategies

gem 'omniauth-twitter'

There is no base omniauth that we need to add.
The strategy gems depend on the base omniauth gem, and they will fetch it.
3. Write an omniauth initializer
in config/initializers: any code there will be run once – no naming standard
Create a file called config/initializers/omniauth.rb
Add this:

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :developer unless Rails.env.production?
  provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end

In routes put

match '/auth/:provider/callback', to: 'sessions#create'

match will map to any HTTP verb

In application layout: add a signin link

<%= link_to 'sign in with twitter', "/auth/developer" %>

So your user model could just have a column for Provider and UID
You could get other stuff from hash

They have provider :twitter, ENV[‘TWITTER_KEY’], ENV[‘TWITTER_SECRET’]
environment variables are part of operating system
To view them:
env | sort
in irb, type “ENV”
ENV[“PATH”] is the OS “path” environment variables
So you can add it in the environment. It only works on a specific machine. Good luck deploying to Heroku
In terminal:

export TWITTER_KEY="adhflsblsdfbsdlfhsbdlbf"
export TWITTER_SECRET="gpwpilwopohbnmiuhuftttdfg"

heroku config:add TWITTER_KEY="adhflsblsdfbsdlfhsbdlbf"

print them out:

heroku config

2012-03-15_08.28.54
cron tasks:
devcenter.heroku.com/articles/cron

1. create a file lib/tasks called cron.rake
2.
3.
4. desc “import tweets”
5. task :cron => environment do
6.
7. end
heroku rake cron
——————

    <%= f.collection_select(:runner_id,
                             Runner.all, 
                             :id, 
                             :name) %>

a
This is from Entry form. Entry belongs_to runner, runner has many entries
So :runner_id is the field in Runner, id is from runner, name is also from runner
foreign key, table, what to save as the foreign key, what to display

Code Academy Week 9 Notes

2012-03-06_08.01.48
Shay Howe: design is not a veneer, it is very important
HTML: Markup (content, structure, meaning)
CSS: presentation language (style)
HTML: elements, attributes, tags
Elements: designators that build objects on a page
Attributes: provide more info to element
tags: elements and attributes together
elements can be block and inline
block: bigger, larger elements of the page, push everything else below them
inline: do not begin on a new line
head is metadata for browsers, servers, etc
body: what the user sees

CSS: selectors, properties and values
selector is an HTML element
property: style to be applied
value: behavior of property
id and class selectors in addition to element selectors
ID can be used once on a page
class can appear many times on a page
ID is with a pound, class with a decimal point
#logo – ID
li.tumblr – class
you can chain them

ul#social
ul#social li
ul#social li.mail

the box model
every element is a rectangle
has height, width, can have border, padding and margin
adding border, padding and margin will increase the size of the box

floats:
can float to the right or left
long-hand numbers for margin, padding: top, right, bottom, left: clockwise
You may have to clear stuff

.clear {
    clear: both;
}

Back to Jeff:

@flights = @flights.joins(:departure_airport)

Until you call .all or .each you can keep chaining methods on the proxy
joins method: put in a symbol that is a has_many or belongs_to symbol
You cannot just pick anything you want
You can chain them

@flights = @flights.joins(:departure_airport => :restaurants)

Now: John McCaffrey, a mentor
@J_McCaffrey
What happens next?
don’t waste time doing stuff you’ve already done before
Capture what you know, from books, people, etc
Write it all down
Take lots of notes, make them searchable, reachable
Tools: Editor, Evernote, GoogleDocs
He gets pdf versions of all the tech books he buys/reads, puts them on Google docs, so he can search

Code = Executable notes
save and organize your projects
create tests to document what you know
follow interesting projects on github

Links and sites: Write them down, google history, delicious

User other people’s notes:
gem install cheat
it gives you other people’s notes

Local docs:
gem server: starts a local server, then go to
http://localhost:8808

gem install yard

Look into ri and rdoc to get local documentation
sdoc is good

Do what you can to capture what you know right now
When you find something useful, write it down

What about afterward:
Finish Hartl tutorial
He said many people die after chapter three. I personally have no idea why.
CodeSChool.com
railsforzombies.org has some ruby jobs – also a good tutorial
rubykoans are good, since a lot of Rails people hit a wall because they do not know a lot of Ruby
Javascript: ejohn.org/apps/learn – good thing to know – knowing JQuery is a good way to get ahead
RailsCasts
peepcode.com: pay site
Getting help:
20 minute rule: If I can’t figure it out after 20 minutes, start asking. Sometimes asking the question can help you figure the answer
Campfire/IM:
Local docs
Stackoverflow.com

Google better:
exclude with –
“quoted search”
fuzzy search ~
site:specific search
define:antidisestablishmentarianism
range ’28gb ssd $100..$230′
Time in New York

how to ask a tech question:
Do some background search
Document what you’ve tried
Find the right place to ask
Post your question with summary
Link to full details (gist)
be willing to back up a few steps
Post the resolution

Honing your skills:
can you build a report, parse a spreadsheet, keep builing apps – a lot of them
help the next batch of CA students
help out on Stack Overflow

Build your profile:
github, heroku, workingwithrails.com

Freelance:
elance.com, odesk.com, rentacoder.com, donanza.com, cloudspokes.com

Build stuff
colloborate wiht CA students
participate in startup weekend
look for volunteer opportunities: taprootfoundation.org, grassroots.org, overnightwebsitechallenge.com

techstars.org
killerstartups
startupsopensourced.com

master your info
collaborate
—–
Back to shay :
Take Eric Meyer’s reset CSS file
Puts it in app/assets/stylesheets/global

How to change the order of the stylesheets?
In application.css:

*= require global/reset
*= require global/global

the aside tag: This will put stuff over to one side. I think.

He makes a stylesheet called mobile.css.scss. He wants to load it last, so he has to go into application.css and adds all the other ones, and puts mobile.css last

Put a media query in that style sheet. Everything that got a width somewhere else gets a width here

@media screen and (max-width: 640 px;) {
    #container {
        width: auto;
    }

    nav {
        display: none;
    }
    aside, section {
        border-width: 1px 0;
        margin: 0;
        width: 100%;
    }

}

He is using a chrome plugin called window resizer

—-
Back to Jeff

Javascript:
A whole new language
Has nothing to do with Java
Same IPO pattern: input, process, output
Sort of object-oriented
more function-oriented
Define functions, pass function as a argument to another function
Runs inside the browser

Why Javascript?
1. To change HTML code in the browser
You can respond to user events
2. For asynchronous HTTP requests. More subtle, more powerful
This is how Google maps is done

Ruby vs Javascript

def say_hello(name)
  puts "Hello " + name
end
function sayHello(name) {
    alert("Hello " + name);
};

parentheses in javascript are required
semi-colon at the end of the line
Another semi-colon to close function

Functions without names:

do |name|
  puts "Hello " + name
end
function(name) {
    alert("Hello " + name);
};

HTML support:

<script type="text/javascript">
    // code goes here
</script>

In HTML5, javascript will be the default target, so you can just say
<script>

How to call the function:

function saySomething() {
    //  jasldf
};
saySomething();

Obtrusive Javascript: how it was done for a long time
To comment out: // stuff
Or /* jfjfjfj */
Like in C, C++
In the h1 tag:
<h1 oclick=”saySomething()”>
Header
</h1>

callbacks:

function speak(f) {
    alert("");
    f("Jeff");
};
speak(function(name) {
  alert("Hello " + name);
});

 

JQuery in Rails:
Rails 3.1+ has built-in support for jQuery Core and jQuery UI
jQuery UI is not included by default

JQuery will usually start with dollar sign
<p>Hello</p>
$(“p”)
You put a CSS selector in the call
This will return 0 or more elements that match the CSS criteria
$(document).ready(f);
This will grab the whole document, and call the ready method, supply a callback function
Or you could just do

$(f);

$(function() {
});

Lab:

rails new jqueryapp
rails g scaffold products title:string
rm public/index.html

In routes:

root to: "products#index"

 

rake db:migrate
rails s

In app/assets/javascripts/application.js

$(function() {
alert("hello");
});

2012-03-08_08.38.45
To get jQuery to work:

<script src="http://code.jquery.com/jquery.min.js">
</script>

in the head. For some reason you have to close the tag with another closing tag, instead of just the ” />”

How would we work this into a Rails app?
User story: I want to write an app that will maintain my personal Aha! list

get calendar from jqueryui.com
Datepicker: http://jqueryui.com/demos/datepicker/
We will put this in our app somewhere:

<script>
    $(function() {
        $( "#datepicker" ).datepicker();
    });
    </script>

add this to app/assets/javascripts/application.js

//= require jquery-ui

go to the form and make the date field a text field

Can we do a delete without a full request cycle?
Now, we want to change destroy
AJAX: Asynchronous Javascript And XML
Asynchronous: The user does not have to wait
XML: It could be JSON or HTML
3-step recipe
1. :remote => true
You can add this to any link or form. It then becomes an AJAX request, instead of a non-blocking request
2. Respond to JS: enhance your respond_to block to accept JS requests
3. Generate a JS response: instead of HTML.

Go to the index page

<%= link_to 'Destroy', entry, confirm: "are you sure", :method => :delete %>

Add another option

<%= link_to 'Destroy', entry, confirm: "are you sure", :method => :delete, :remote => true %>

Go to the controller action destroy

respond_to |format|
  format.html { redirect_to entries_url }
  format.json { head :no_content }
  # add format.js
  format.js
end

Then create app/views/entries/destroy.js.erb, so format.js has something to render
We can embed Ruby in this template. Jeff will write some JQuery that will execute

$("#...").hide()

How to get the CSS ID?
In the index table, put an id in the tr field

<tr id="entry_<%= entry.id %>">

Prepend entry_ in case we have multiple tables
That ID will be sent in the link_to for destroy

$("#entry_<%= @entry.id  %>").hide()

We have @entry in the destroy action

We could refactor

$("#entry_<%= @entry.id  %>").hide();

In the index page, change tr to use dom_id:

<tr id="<%= dom_id(entry) %>">
$("#<%= dom_id(@entry) %>").hide();

or

$("#<%= dom_id(@entry) %>").fadeOut();

For the create.js.erb

$("#tableid").append("<tr><td>");

create a partial
from table row in index.html.erb

<% @entries.each do |entry| %>
  <%= render 'entry_row', :entry => entry %>
<% end %>

in the partial
<tr>

</tr>

So in JS:

$("#tableid").append("<%= render ('entry_row', :entry => @entry) %>");

You need another helper
Some of the markup will have quotes in it. That can mess up the Javascript
So do this:

$("#tableid").append("<%= escape_javascript(render( 'entry_row;, :entry => @entry)) %>");

Or just use the synonym “j”, but escape_javascript is clearer

Don’t forget the

form_for(@entry, remote: true)

Image from the “Prayers and liturgical pieces from Orient and Occident”, a 15th century manuscript housed at Burgerbibliothek of Berne; image from e-Codices. This image is assumed to be allowed under Fair Use.

Code Academy Week 8 Notes

2012-02-28_08.18.14
undefined method `model name` for NilClass:Class
Means there is a problem with the model
So instantiate it in the controller from the session

How to override application.html.erb for a controller or action

For orders controller, app/views/layouts/order.html.erb
To specify layout:
in controller:

layout 'application', :only => :index

or in def new:

def new
   @cart = Cart.find(session[:cart_id])
   @order = Order.new
   render :layout => 'orders'
 end

we need to encrypt the credit card number. Look in config/application.rb
We will look at
config.filter_parameters +=[:password]
This will filter password out of the log
So we can add to the array
config.filter_parameters +=[:password, :card_number]

asset pipeline: We will talk about it throughout the week. Look in the assets folder. Images, javascript and stylesheets.
It takes all the javascript and puts it in one file, so the browser only has to make one request
Same for css
For css, you should go to application.css and specify files and/or directories

*= require_self
 *= require_tree

require_tree will do everything aplhabetically. You can put them in your own order.

*= require brands
 *= require products
 *= require reviews
 *= require scaffolds
 *= require users

In development mode, there is no asset pipeline. You use it in production.

In config/environments/development.rb

config.assets.debug=false

if you set that to false, you won’t see the GET requests in the logs for EVERY js and css file

Jeff can get to other order pages as well as his own
We have authentication. What about authorization?
In orders controller:

def show
   @order = @user.orders.find(params[:id])
 end

WHat if that ID is not in the order table?

def show
   @order = @user.orders.find(params[:id])
   if order.nil?
     redirect_to root_url, :notice => "Nice try"
   end
 end

You could do this:

redirect_to root_url, :notice => "Nice try" if order.nil?

But then it looks like redirect is the default.
Or

redirect_to root_url, :notice => "Nice try" unless order

Moving this to a one-liner could make it a but confusing
You could also do

if order.blank?
   redirect_to root_url, :notice => "Nice try"
 end

or

unless @order
   redirect_to root_url, :notice => "Nice try"
 end

Stay at same level of abstraction throughout the html.erb files
if you have render tags with low-level html, that could look bad

Class method that makes an ActiveRecord call
Use the scope facility
Instead of:

def self.most_recent
   order("updated_at desc").limit(3)
 end

 

scope :most_recent, order("updated_at desc").limit(3)

scope creates a class-level method, and returns rows
You cannot just return one row

Maybe we want to pass a param from the view to the class-level method or scope

Easy for method.
For a scope:

create a lambda: create an unnamed method on-the-fly
 scope :most_recent, lambda { |n| order("updated at desc").limit(n) }

Orders Controller:
We have a before_filter
We have model callbacks in cart_item.rb
Those are sort of like lambdas as well.
We do not call it, Rails calls it for us at some point.

Let’s do a scope on price for products:

scope :expensive, where('price > 50')

Then in the view you could chain the scopes

Lambda with a default value for min:

scope :expensive, lambda { |min=80| where('price > #{min}') }

Getting the data you want:

.find
 .find_by_*
 .where(hash)
 .where("SQL")
 .where("SQL", ....)
.where("color = BLUE''") # sql syntax - single = sign is comparison
 .where("color like 'BLUE'")

You can also use % for wildcards

.where("name like 'M%'")
 .where("name like ?", "M%")

In Products Controller:

@products = Product.where("name like '#{params[:search]}'")

or

@products = Product.where("name like '#{params[:search]}%'")

So why not do this? Jeff will explain
You could get SQL injection
So do this:

a = params[:search]
 @products = Product.where("name like '%#a%'")

Use the question mark placeholder

@products = Product.where("name like ?", params[:search])

ActiveRecord will create the SQL for you
Fuzzy search:

@products = Product.where("name like ?", "%#{params[:search]}%")

Then in the controller you could chain the methods

@products = @products.limit(1000).order('name asc')

It is not until you get to the @products.each (or a .all) in the view that you run the query

Should you use the products controller for searching, or make a search controller?
the form_tag goes to ‘/products’ with a get, which will go to the index action
—-
New app:
User Story Analysis
1. Identify resources
2. Create Models
3. Implement business rules
4. Create User Interface

Some people go in the opposite order

Air Academy User story
1. As a visitor, list the flights

In Rails 3.2, when you generate model, if you do not specify the types it will assume that it is a string
rails g model Airport code:string city:string
ericm@finance:~/ruby/ca_files/air$ more db/migrate/20120228174012_create_airports.rb

class CreateAirports < ActiveRecord::Migration
  def change
    create_table :airports do |t|
      t.string :code
      t.string :city

      t.timestamps
    end
    add_index :airports, :code
  end
end
rails g model Airport code:string city:string

emacsnw db/migrate/20120228174012_create_airports.rb

For flights, we need two airports, not just one departure_airport_id, arrival_airport_id

class Flight
  belongs_to :departure_airport, :class_name => 'Airport'
  belongs_to :arrivale_airport, :class_name => 'Airport'
end

If you say belongs_to :blah, the table needs a column blah_id
If that is the only belongs_to, Rails will assume there is a Blah model

rails g model Flight departure_airport_id:integer, arrival_airport_id:integer number:string distance:integer duration:integer departs_at:time

2012-03-01_08.38.49
Pagination:
Kaminari, Will_paginate, roll your own

User story: As a user, I want to make a reservation
As opposed to doing something “as a visitor”
Different permissions, etc
So for “As a user” that user story needs an account
User story analysis
1. Identify resources
2. Create models
3. Implement business rules
4. Create user interface

reservation model has user, a flight, chosen departure date, credit card number
Associations:
user can have many reservations
flight has many reservations
reservation belongs to flight and belongs to user

rails g scaffold Reservation user_id:integer flight_id:integer credit_card_number:string departs_on:date

departs_on for dates, departs_at for times

How to decide to model or scaffold? How much of scaffold will you use?

add_index on the reservation table
add_index is outside the create_table block

add_index :reservations, :user_id
 add_index :reservations, :flight_id

Good to have indexes for foreign keys
Then run

rake db:migrate

rake db:migrate:reset will drop database and recreate tables
rake db:seed
You could do

rake db:migrate:reset db:seed
rails g model User first last email passwod_digest

——————
Now JC from DevMynd is talking
database: structured set of data on a computer, accessible in various ways
five categories: relational, graph, key-value, document, column family databases
Relational database: built around relational theory (first-order predicate calculus), schema defined in tables of columns and rows, data is related through matching keys
Graph: based on graph theory. These DBs use nodes, properties and edges to describe a “web” of data. They can be powerful for complex ancestral queries (Amazon: People who bought X bought Y)
Key-value: primary way of retrieving objects is by a single key. What can be stored as a value varies.
Redis is used for queing systems
Document database: storing document-oriented, semi-structured data. Normally within a loose schema and the ability to store/retrieve nested structures
Column-family database: inverse of relational model. Big table.
Choosing data store can be pretty complex.
Considerations: indexing, querying, scaling, modeling, mapping, analyzing, recovering
Indexes: a parallel description of your data optimized for fast lookup
If you will ever do an order_by or a conditional query
Finding by department and last name is different than index that finds by last name and first name
Querying: getting info from db. Do we use a template object, a query language, or a string key?
Mongo can use query syntax, or you can pass in a template doc
scaling: scale up (faster, bigger hardware) or out (distributing data, indices and queries across more machines, aggregating the results)
mongo can shard well, so can redis
modeling: is your schema fixed or flexible? a few large things, lots of small things
Mapping (ORM) – ActiveRecord for RDBMS, Mongoid for MongoDB, Redis ruby driver
how will you interact with db?
analysis: what does the database provide?
recovery: relational: replication, push log to another system
Mongo: backup and restore tools
Heroku, other cloud backups are not that great

optimization: this is usually the first bottleneck
universal: careful indexing, duplication
relational: de-normalization, pivoting, materlialized views
normalized: each concept in a different table, less repetition
pivot: making rows into columns, and vice versa
materialized views:
non-relational: nest relationships, parallel queries
downside of indexing: it can take a LOT of space, plus index might be held in memory instead of disk
Put query logic in your model, not your controller
So if you change the datastore, you can just change it in the model class
relational tables good for complex joins
Think carefully about uniqueness and nullability early on

——————
Back to Jeff
For flight page, give some info about flight
the user is part of the session
reservation for
So in reservation controller, in new method: @user = User.find(session[:user_id])
You could do it from show page for a flight
@user = User.find()
Get stuff from flight show page
Reuse the flight_details partial

But we could get a Nil
So in the reservations controller
We will do something in def new
We could have a link from flight show page
@flight.id) %>
So in new,

@flight = Flight.find(params[:flight_id])

So we want to put that link in an if on the flight show page
Put a filter on the reservations new controller

before_filter :require_login, :only => :new
   def require_login
   if session[:user_id].blank?
     redirect_to root_url, notice: "Get your act together"
   end
 end

@flight.id) %>

In reservation form:

in reservation controller.new:

@reservation.flight = @flight

validation on reservations:

create method in reservationcontroller:

def create
   @reservation = Reservation.new()
   @reservation.user = User.find(session[:user_id])
 end

Sending email in Rails – it could depend on your host

rails g mailer ReservationMailer
 rails g mailer ReservationMailer

In our reservation controller, we will use this in respond_to block

email = ReservationMailer.confirmation(@reservation)
 email.deliver

in ReservationMailer

def confirmation(reservation)
   @reservation = reservation
   mail(:subject => "Thanks for your reservation",
   :from => "reservations@academyair.com",
   :to => reservation.user.email )
 end

So in app/views/reservation_mailer/confirmation.text.erb
Hello, ,
Thanks for sending us $300.

Flight details
———————
Flight number:

Image from World Digital Library, assumed allowed under Fair Use. Image from the Ashburnham Pentateuch, or Tours Pentateuch, a Latin manuscript of the first five books of the Old Testament from the 6th century or 7th century. Its place of origin is unknown.

Code Academy Week 7 Notes

2012-02-21_08.02.14

3 more weeks of core material
The building weeks there might be breakout topics
This week:
Model callbacks
User auth
Nest resources
Search
Pagination
Mailers
Environmental variables

Weeks 8-10
Twitter/Facebook auth
File uploads
Credit cards/PCI
HAML
Asset pipeline
Javascript and JQuery
AJAX
Coffeescript
Database Scaling
RSpec/Testing

Model Callbacks:
For a user story:
As a user, I want to see the total price in the shopping cart before I check out.
When jeff did it, he put it in the view. This is generally considered bad. Need to calculate outside the view.
How about showing total of the Cart?
So we need to add that column, since we don’t have one now.
Or add a method to the cart

def total
    sum = 0
    cart_items.each do |item|
        sum = sum + item.product.price
    end
end

Why not do this in the controller
Views cannot call controller methods
You also might need to know the total in another page
But do not call number_to_currency on sum in the model. Do not do any formatting in the model, do not calculate in the view.

Now he is doing total with inject method

cart_items.inject(0) do |total, item|
     total + item.product.price
end

You give it 0 arg because that is where you will start. It is another way of doing +=
It returns the final total at the end
Or on one line:
cart_items.inject(0) { |total, item| total + item.product.price }

————————-
@fredlee from ENova is here.
How to succeed at Enova:
– Skillnacity: skill + tenacity. He thinks tenacity is important. Skill can be learned.
– Takes initiative: it is better to ask for forgiveness than permission.
– Selfish giver: willing to give and take
– Networking: Bell Labs: star engineers were good at networking

His thoughts on Design
– Every design decision trends towards “wrong”
– or, every design get a little more wrong each second. The world changes
– design does not matter. Kind of.
So what does matter?
1. Tests. Preferably automated tests that validate system behavior.
2. Short iterations
3. Courage to throw it all away.

Too much technology!
xml, html, css, js, json, erb, yaml
This too shall pass
So what stays the same?
– Users first!
– Speed/scale/performance
– Money (your ability to generate revenue validates your purpose)

Thoughts On Code Quality:
– It does not matter. As long as it works. But higher quality is better
– Lean Startup: If you do not know who the customer is, you do not know what quality is
– Quality is defined by user
– Or, there is no universal objective definition of quality

——————-

Back to Jeff
CartItem model. Create one in memory, add/edit attritbutes, save it. You might later change it, later delete it.
.new
.save
.update_attributes
.destroy

Model validations can affect some of those methods. You cannot save an invalid object.
So first some validation runs. 1 of 2 things will happen.
The Creation case or the update case.
The create path is the first time this object goes into database. It will assign an ID to that object.
If it has already been saved, it will do the update case.
Which case is run will determine the callbacks you can run.
After creation, we can update a total column in the cart.
We write a hook method for callback. Callback meaning we write it but we do not explicitly call it. Rails will call it.
So we run a migration to add a total to the cart.

rails g migration

 

def change
    add_column :carts, :total, :integer, :default => 0
end

That could also go in an “up” method
If I want to undo it, make a “down” method

def down
    remove_column :carts, :total
end

# I missed a bit in here due to wireless issues
So now we have a total method, but Jeff already defined a total method
His version will take priority. You can redefine methods.
But it is not a good idea

So in CartItem model:
Add a callback:

after_create :increase_cart_total

Look at the guides to find the callbacks. The symbol is the name of a method that Rails will call.

def increase_cart_total
    cart.total += product.price
    cart.save
end

We could do this in the cart_items_controller
But what if I manipulate my models some other way
Callback: When one model changes another model
This after_create is creation in the database, no necessarily the controller “create” method.
Model callbacks: business process events.
Controllers generate the response. If you can have models talk to each other, that is better.
Javascript and jquery use a LOT of callbacks.
1. Add a total column to the cart model
2. Show the total inside the cart in the view
3. Add an after_create callback to update the total whenever a new cart item is created
rails g migration AddTotalToCart total:integer

The user model:
1. Add “bcrypt-ruby” to your Gemfil
2. Create a User model that includes a string column named “password_digest”
3. Use “has_secure_password” in the model

The user form will have attributes password and password_confirmation, even though they are not in the database. Only password_digest is a column. has_secure_password adds those memory-only attributes.
has_secure_password will also validate that the two password fields are the same
Add a login field.
He did not get in, so he used the logger method
logger.debug “Started sign in action”
Make the link to sign out go to /logout
In routes:

get '/logout' => 'sessions#destroy', :as => :logout

Session is not a regular ActiveRecord class
In the destroy method:

reset_session
redirect_to

2012-02-23_08.16.47
Authentication (who are you) versus authorization (what can you do)
Authentication: indentifying a user, making them identify themselves – usually username and password
Authorization: Permissions

Only let people check out if they are checked in. You could put this inthe shared/cart partial:
button_to “check out”, orders_url if session[:user_id].present?

Or you could do it in the checkout action
In OrdersController.create:

if session[:user_id].nil?
    redirect_to root_url, :notice => "Please check in"
end

This could give the double render error
the redirect_to has not effect on control flow. You should end the if block with “return”

if session[:user_id].nil?
    redirect_to root_url, :notice => "Please check in"
    return
end

But we would need that in the index method as well. That gets messy.
You can also call show with /orders/6
We don’t want this code in three places. How to DRY up controller code? Before filters.

before_filter :require_login

def require_login
    if session[:user_id].nil?
        redirect_to root_url, :notice => "Please check in"
        return
    end
    @user = User.find(session[:user_id])
end

Since we get @user in the filter, we ccan remove all the User.find method calls
If the filter renders or redirects, the action will not be run.

To list all the tables from within the console:

ActiveRecord::Base.connection.tables

In shopping app, we want to remove the item from the cart.
So in CartItem we put in another callback: after_destroy

def decrease_cart_total
    cart.total -= product.price
    cart.save
end

We can just call product since we have belongs_to :product in the model
after_destroy is better. It will keep it in memory after it deletes the row in the database. It is better to do after_destroy instead of before_destroy since something may go wrong between before_destroy and the actual destruction

Now we want to add some administrators to manage product catalog.

rails g migration AddAdministratorToUser administrator:boolean

Let’s change the migration file:
add_column :users, :administrator, :boolean, :default => false

you can use conditional logic in the view:
Instead of class.boolean == true
you can say
class.boolean?

<% user = User.find_by_id(session[:user_id]) %>
<% if user.present? && user.administrator? %>

In all those pages. There has to be an easier way.
Put this is a helper. Partial is good for markup. Helper is good for logic.
app/helpers/application_helper.rb

def administrator?
    user = User.find_by_id(session[:user_id])
    return user.present? && user.administrator?
end

In the pages, do this:

<% if administrator? %>

Now we want to sort the data. Use the order method. We have done Product.all, Product.first, etc, now we have

Product.order("$COLUMN_NAME, DIRECTION")

You can also call it on the association proxies

@products = Product.order("name asc")
Product.order("LOWER(name) asc")

To limit how much you get back:

Product.limit(n)
Product.order("price desc").limit(3)

Most recently added item:
application layout file:
Above the cart:

<div id="news">

<%= Product.recent_items.each do |product| %>
    link_to product.name, product_url(product)
<% end %>
</div>

We don’t have Product.recent_items,
But we have columns in database: created_at and updated_at

Product.order("updated_at desc").limit(3)

But let’s not put that in the view. That could be in the controller instead of the view. Or in the model.

def most_recent
    Product.order("updated_at desc").limit(3)
end

So in the view you can say Product.most_recent.each.do
But this is not an instance method. We want this to be a class method.
So you can do it this way:

def Product.most_recent
    Product.order("updated_at desc").limit(3)
end

or

def self.most_recent
    Product.order("updated_at desc").limit(3)
end

So you could even do this:

def self.most_recent
    order("updated_at desc").limit(3)
end

Or self.order. But if you did that, you would still need “self” in the method signature to keep it a class method.

Image from Wikimedia, assumed allowed under Fair Use. Image from the Ambrosian Iliad, a 5th century manuscript of the Iliad.

Code Academy Week 6 Notes

2012-02-14_08.04.44
product has many reviews
There is a proxy for the data – it is a subclass of Array

@review = Review.new
@review.product = Product.find(params[:product_id])

What is there is no product with that ID?
The “find” method will raise an exception (actually params[:product_id] is nil)
How to make it more forgiving

if params[:product_id].present?
    @review.product = Product.find_by_id(params[:product_id])
end

the find_by_* methods (aka dynamic finders) are more forgiving
You could even get rid of if

How to hide the product pull down in the review form?
Hidden form field
In _form.html.erb for review:

<% if @review.product.present? %>
    <%= f.hidden_field :product_id %>
<% else %>
<div>
    <%= f.collection_select :product_id, Product.all, :id, :name %>
</div>
<% end %>

Why do we need an equal sign for if it’s a hidden field?

<%= f.hidden_field :product_id %>

It still needs to be emitted to the HTML
In Rails, we have 2 methods: present? and blank?
blank? is like nil?
if a string is ”  “, that is not nil, but it is blank
present? is the opposite of blank?
Why have both? Just negate one of them.
!a.blank? is “not the Ruby way” according to Jeff

[1,2,4].map{ |n| n*2 } is just like [1,2,4].collect{ |n| n*2 }

Matz does not like minimal interface. Sometimes map will feel right, and sometimes collect will.

[1,3,5].each do |n|
    puts n
end

map is an iterator, like each

w = [1,3,5].map do |n|
    n * 2
end

map wants a return value from each iteration of the block

<% if @review.product.present? %>
could also be
<% if @review.product %>

show.html.erb for reviews has this at the top:

<%= notice %>

This method will emit what ever is in the :notice key in the redirect from your controller
This will only live long enough to be redirected
This is called a flash message in Rails
it is a hash
the “flash hash”
You could also set the notice just before the redirect_to

flash[:notice] = "Way to go!"

You could make it flash[:zebra]
and call

<%= flash[:zebra] %>

in the html.erb file

http is stateless, so each request has to provide all the information the next request needs
Putting the query string in the URL has been one way to keep information
User story:
as a user, I want to add several products into a shopping cart
Jeff does it:
Carts and Products
This is many to many
But many carts will want to have products
Make a join model in between
CartItem
Cart has_many :cartItems
cart_item belongs_to a single :cart
A product will have many cart items
a cart item will belong_to a product
cart_itme will have cart_id and product_id

rails generate model Cart name:string
rails generate model CartItem cart_id:integer product_id:integer quantity:integer
rake db:migrate
class Cart
    has_many :cart_items
end
class CartItem
    belongs_to :cart
    belongs_to :product
end

add has_many :cart_item to product
The file name is Pascal case. In code or console, you use underscores

Jeff says the modelling is the hard part of Rails
In the console, you can do this:

cart = Cart.new
cart.cart_items
item = CartItem.new

in console, this will reload items from database
cart.cart_items(true)
or: cart.cart_items.create :product => Product.last
cart.cart_items.build will make a new cart in memory only.
cart.cart_items.new does not exist on the proxy

Add item to a cart. How to add another item to same cart?
Use cookies
Session data
Each has a name and a value
name/value pair, like a hash in Ruby
Expiration is optional – session by default
cookie data lives in the browser
How to add cookies:

session[:name] = value

Each cookie is limited to 4K of data
Do not put an ActiveRecord object into a cookie
Cookies are stored on the client machine
deal with session hash in your controllers
It is defined in ApplicationController’s parent
session[:cart_id] = cart.id
The session data is encrypted
In the create method for Cart controller:

if session[:cart_id]
    cart = Cart.find(session[:cart_id])
else
    cart = Cart.create
end

Put the cart stuff in a partial that everything can see.
app/views/share/_cart.html.erb

<%= render 'shared/cart >

Instead of accessing session hash inside view, make a helper method
Use view helpers

Seed file
Pagination
Seed file will help you pull in test data

Vince did pagination

Checkout: cart becomes an order
Cart partial:

<%= button_to "Check out", orders_url %>

In routes:
resources for :orders
Create an orders controller

def create
    # do stuff
    # now clear session data
    reset_session
    redirect_to products_url, :notice => "Thanks for your order"
end

Look at guides for sessions and cookies

2012-02-16_08.20.30
In grandma example, they used a form_tag, not a form_for since they did not use a model.
form_tag(“/ask”, :method => “get”) do
put form tags here

routes:
get ‘ask’ => ‘grandmas#ask’

What we started:

input = ""
output = ""
puts "Talk to grandma"
while input != "BYE"
    input gets.chomp
    puts "What?"
    if input == input.uppercase
        puts "No, not since #{rand(1930..1950)}"
    end
end

Jeff recommends irb or rails console

Two methods:
a.upcase will check if the string contained in a is uppercase
a.upcase! will change the string to uppercase

Some people used regular expressions

Now going back to the shopping cart.
New models: Order, OrderItem

reset_session will reset the whole session
how to just get rid of cart?

session[:cart_id] = nil

Cycle through the cart creating order items, and call order.save afterwards. Fewer transactions.

New app for users

rails g model Item name:string value:integer
rails g model User name:string email:string password:string

Do not store passwords as strings. We will go over that later.

You could put this in the seeds.rb:

Item.create :name => "Hockey Stick", :value => 100

etc, etc, etc,

rake db:seed

To wipe out existing items in database, you could add this at the top of seeds.rb
Item.destroy_all
He added users and items to routes with resources

rails g controller Items new create show
rails g controller users new create show

Signup is easy: Just add user to database
Signin and signout are session management
If they are in database, when they sign in just make a session cookie

We create a sessions controller, inherits from application controller

SessionsController
    def new
    end

    def create
    user = User.find_by_name(params[:name])
        if user.present?
            if user.password == params[:password]
                session[:user_id] = user.id
                redirect_to items_url, :notice => "hello"
            else
                redirect_to items_url, :notice => "Nope"
            end
        else
            redirect_to items_url, :notice => "Nope"
        end
    end

    def destroy
        # reset_session
        # Or
        session[:user_id] = nil
        redirect_to items_url
    end
end

There will also be a folder for sessions, with a new.html.erb
We use form_tag instead of form_for since we have no model

<%= form_tag "/sessions" %> (or sessions_url)
    <% label_tag :name  %> <%= text_field :name  %>
    <% label_tag :password  %> <%= text_field :password %>
    <% submit_tag 'Sign In', new_session_url %>
<% end %>

Now in app layout:
if session[:user_id].present?
Hello, User.find(session[:user_id]).name

In routes:
post “/logout” => ‘sessions#destroy’, :as => :logout
link_to “Sign Out”,
button_to will create a post

Make the password a password_field_tag
To do password confirmation:
add a text field in form: password_confirmation, which you can do even though we are in a form_for
Then in model for User:
validates :password, :confirmation => true

For password security:
add “bcrypt-ruby” to Gemfile, run “bundle install”
To user, add a column called “password_digest” as a string
add line “has_secure_password” to the model

rails g scaffold User name:string email:string favorite_color:string password_digest:string
rake db:migrate

If you make a mistake,

rake db:migrate rollback STEP=1

Put line “has_secure_password” into the model
For user form partial:
Remove the password digest field from the form
Put in password and password_confirmation

Create an account and sign in at the same time
In users controller in create

if @user.save
    session[:user_id] = @user.id
end

So how do people sign in? We don’t want them to know their digest
In console:

u = User.find_by_name("Joe")
u.authenticate("hockey")

That should work
It will encrypt the input, it will not decrypt the string in the database

Image from Wikimedia, assumed allowed under Fair Use. Image from the Ambrosian Iliad, a 5th century manuscript of the Iliad.

Code Academy Week 5 Notes

2012-02-07_08.32.40
He went over SQL in Ruby/Rails
Team has many players, Player belongs to Team

User story:
As a user, I want to see a list of products I can buy
A product has a name, color, and price. A product belongs to a single brand.
Prices are always in exact dollar amounts (no cents).
As a user, I want to add a review to a product
A review has a rating from 1-5 and a brief description

new rails app
products and brands
products belong to brand, brand has many products
Generate scaffold for brand and product
go back to index after create

Go over the scaffold
To get the brand in the collection select
Go to the form partial for the product
Only change the number field, not the label field
brand_id is the foreign key

<%= f.collection_select :brand_id, Brand.all, :id, :name %>

:id is param for Brand.all, :name is the field in the brand. That is what will be displayed
You may not want to always do Brand.all. We will go over that later.
View should not decide what data to show.
Put a variable in the new method in the controller

Now listing the products, we still get the brand ID

Make the description for a form a text field, not string

f.collection_select :product_id, Product.all, :id, :name

For rating, we want a list of  to 5

f.select :rating, [1,2,3,4,5]

You should still add a validates method in the model
What if you want 1 to 100?
There is a way to do a range

:rating, (1..100).to_a

to_a converts it to an array
Make the description box smaller. Go to the form partial
:rows => 5

Gems:
You can have more than one version

gem install rails

You may see:

sudo gem install rails

That will install it with admin rights
With rvm: never use sudo
It will install latest by default
gem will handle dependencies
railties is the guts/engines of rails
You can call
gem sources
to see where it will look for gems

Vince’s app:
We could edit the Gemfile

gem 'gmaps4rails'

Then run

bundle install

Back to Jeff
How to get words to appear on pull-down
Numbers:

f.select:rating, (1..5).to_a

Or

f.select:rating, [1,2,3,4,5]

or

f.select :rating, {"Excellent" => 5, "Very Good" => 4, "Okay" => 3, "Not so good" => 2, "Bad" => 1}

To validate that the rating will be between 1 and 5
Jeff starts with the guides
Jeff used

validates :rating, :numericality => { :only_integer => true }
validates :rating, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1, :less_than_or_equal_to => 5 }

Test in the Rails console

2012-02-09_08.25.05
To support 1 URL: pages/social
One way:

rails g controller pages social

rails new friendBC
cd friendBC

-> Memorize the routes for resources
in routes.rb
get “pages/social”
in app/controllers add a controller: PagesController < ApplicationController
add a method called “social”
add app/views/pages/social.html.erb
get an image, put it in

<% image_tag "logo.png" %>

in assets/global directory
Make the background grey
app/assets/stylesheets/application.css

How to get JSON data?
He put some stuff in his controller

require 'open-uri' and require 'json'
result = JSON.parse(open("Some URL").read)

Put result in view file
In hashes, symbols and strings are not interchangeable. Usually they are.
To get the image:
in the view:

<%= image_tag @first_result["video"]["thumbnailUrl"] =>
 <img src="@first_result["video"]["thumbnailUrl"]">

Now he is calling @result @channel

Now Jeff is going through it
Agile practices: single responsibility, clear intention, DRY
These are the top 3
Rails cries out to help you do those things
When you download someone else’s code, you may need to run “bundle install”
Jeff moved some of the HTML onto a partial
Then change the variable in partial to one called “channel”
Then in the view call

<% render 'ribbon', :channel => @Whatever %>

In the partial, do not use raw “a” and “img” tags

<% link_to "Video goes here", "http://www.youtube.com#{post["video]["hostId"]}" %>

Now add the image:

<% link_to image_tag(post["video]["thunmbnailUrl"], :size => "240x180"), "http://www.youtube.com#{post["video]["hostId"]}", :target => :blank %>

Now back in view, we call the render three times. What if we pull another channel, we will have to add another line.
So in controller, create an array

@channels = [@facebook, @twitter, @youtube]

In the view:

<% @channels.each do |channel_data| %>
    <%= render 'ribbon', :channel => channel_data %>
<% end %>

Now they do not need to be instance variables in the controller
We still have repetition

def get_json_for_source(source)
    return JSON.parse((open("https://")).read)
end

Then in other method:

facebook = get_json_for_source('FACEBOOK')

This is Ruby skillz

A good pattern to know:
An array of strings. You are transforming the array into another array.

@channels = ['a', 'b', 'c'].map do |source|
    get_json_for_source(source)
end

map is like each
Look it up
collect is another good one to look up.

@names = users.collect dp |user|
    user.name
end

Could be

@names = users.collect {|user| user.name}

We saw one-line blocks in scaffolds in index

respond_to do |format|
    format.json {render json: @brands}
end
format.json do
    render json: @brands
end

Look in the dev/tth/shop folder
—————————————————–
Now: git and github
Look up “git – the simple guide”

git init

makes a new repository

git clone /path/to

to checkout a repository
Workflow:
working dir has files, index to stage commits, the head is the last commit
adding and committing

git add <filename>
 git add *
 git commit -m "message"

Now it is in the head, but not remote

git push origin master

afterwards, you can just do git push
To add a branch

git remote add origin <server>
 git checkout -b feature_x
 git pull to update - that pulls down latest changes

to reset:

git fetch origin; git reset --hard origin/master

gitk – is a good GUI
Neal making live changes

git status

He is on master branch

git branch

git status now tells him he made a change

git add .
 git commit -am "updated the Readme"
 git push origin master

or just

git push

There is also heroku

git push heroku master

or

git push heroku

Heroku requires postgres

Neal makes a new app

rails new ca_boat_party

It would be nice to stop an existing rails server
You could also specify a port

rails s -p 4000

It is now live on our local machine

git init

go to github.com
make a new repository

ca_boat_party - same name as directory
 git add .
 git commit -am ""

No good

git remote add origin git@github.com:nealg223/ca_boat_party
 git push -u origin master

Now put it up to heroku

gem install heroku

ssh keys are a pain

heroku create ca-boat-party --stack cedar

They have different stacks. bamboo is the current stack, good for rails up to 3.0. For rails 3.1 use cedar
Now push it to heroku
Update the gem file Gemfile to add postgres

group :production do
     gem 'pg'
 end

Put sqlite3 in group :development
bundle install
now commit changes to git

git add
 git commit -am "changed Gemfile"
 git push

Now push to heroku

git push heroku master

another command: heroku open
assets, like images, there could be some problems
another command is heroku logs
or

  heroku run console

it’s like an irb for heroku

heroku run rake db:migrate

in file app/config/environments/production.rb

set config.assets.compile = true

You can go to gitref.org
————————————————————–
Working with Shop app:
Get the average of reviews for a product

p = Product.find(1)
 p.reviews

Calling product.reviews: It gets rows from our table. It looks like an array, and behave like an array, but it can do more than what an array can do. It returns a proxy class. It is a proxy for the data you want.
So you can say p.reviews.count – it makes an SQL statement
You can do a lot of array stuff: p.reviews.first, p.reviews.sum(“rating”)
Arrays do not have sum method, but ActiveRecord does have sum method
p.reviews.average(“rating”) it gives us a BigDecimal instance
p.reviews.average(“rating”).to_s

Another association concept
A brand has many products.
A product has many reviews.
A brand has many products throught its products.

class Brand < ActiveRecord::Base
     has_many :products
     has_many :reviews, :through => :products
 end

The lines must be in that order
Review does not have brand id, but product has brand id, and review has product ID
So you can just do Brand.reviews without looping
Users want to see average rating for brand
So in brand show page – put it there for each brand
So to brand index page:

<%= brand.name %>

Rating:

<%= brand.reviews.average(:rating) %>

For reviewing the product form, it would be great if it knew which product you were using
No params hash for /reviews/new
Put a placeholder in the route
Put it in URL via ?key=value
Now you have a params hash
In product/show.html.erb

<%= link_to "Review This Product", new_review_url(:product_id => @product.id) %>

So now you see ?product_id=1 in url for new form
so in controller, look at new action in review controller

def new
     @review = Review.new
     @review.product_id = params[:product_id]
     # or @review.product = Product.find(params[:product_id])
     respond_to
 end

so in reviews/new.html.erb
New review for

<%= @review.product.name %>

Next: Leave out the pull-down form. But get product ID
replace collection_select with a hidden field

Image from Wikimedia, assumed allowed under Fair Use. Image from the Vatican Virgil, a 5th century manuscript of poems by Virgil.

Code Academy Week 4 Notes

I only seem to have notes for the second day of week 4.

2012-02-02 Notes

Scaffolding notes:
respond_to
partials: Like a server side include

Look up respond_to method

respond_to do |format|
     format.html
     format.json { render json: @runners }
 end

JSON only:

respond_to do |format|
     format.json { render json: @runners }
 end

You could use curl as well.

514  curl -v "http://localhost:3000/runners"
 515  curl -v "http://localhost:3000/runners.json"
 516  curl -v "http://localhost:3000/runners" -H "Accept: text/html"
 518  curl -v "http://localhost:3000/runners" -H "Accept: application/json"

Try getting a png:

ca-imac1-2: ~/dev/tth/MarathonApp$ curl -v "http://localhost:3000/runners" -H "Accept: image/png"
 * About to connect() to localhost port 3000 (#0)
 *   Trying 127.0.0.1... connected
 * Connected to localhost (127.0.0.1) port 3000 (#0)
 > GET /runners HTTP/1.1
 > User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
 > Host: localhost:3000
 > Accept: image/png
 >
 < HTTP/1.1 406 Not Acceptable
 < Content-Type: image/png; charset=utf-8
 < X-Ua-Compatible: IE=Edge
 < Cache-Control: no-cache
 < X-Request-Id: 0e74fdad7575b392561230a70fb0cadd
 < X-Runtime: 0.001522
 < Content-Length: 1
 < Server: WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30)
 < Date: Thu, 02 Feb 2012 14:42:53 GMT
 < Connection: Keep-Alive
 <
 * Connection #0 to host localhost left intact
 * Closing connection #0

I did not know there was a code 406.

There is a method called responds_with :html, :json, :xml
Not used too often.  That was intended for all actions, but people did not want universal responders.

Scaffold does not provide any security out of the box.

New action also has a block to send json back
526  curl -v “http://localhost:3000/runners/new.json” -H “Accept: application/json”
returns

{"created_at":null,"id":null,"name":null,"updated_at":null}

This could help other developers know what data fields your classes have

The create action has an if block in the respond_to call to handle both a successful and unsuccessful creation.

In Ruby 1.9, you can use a new syntax for hashes

h = {:color => “Blue”, “fruit” => “apple”}

You could also do it like JSON

i = {color: “Blue”, “fruit” => “apple”}

You can only use the colon for keys if your key is a symbol.
So if you mix key types like in hash i, things get a bit ocnfusing. Your value can be a symbol, but that colon must still be on the left.

Assigment: look at the destroy. What is head :no_content about?

Memorize the RESTful Design chart with the routes, URLs, actions, etc

Let’s look at new and edit
TextMate tip: could go to the drawer. There is another way to get there. Command-T pops up a window, type in the name of your file. You can type something in the middle.
Look at the “new.html.erb” page. Where is the form?
Look at the “edit.html.erb” page. Where is the form?
We see this in each file:

<%= render 'form' %>

There is a file app/views/runners/_form.html.erb
Partials begin with underscores.
You just use the render method.
You can use instance variables in the partial.

From index.html, you could take this and put it in a partial:

<% @runners.each do |runner| %>
     <tr>
     <td><%= runner.name %></td>
     <td><%= link_to 'Show', runner %></td>
     <td><%= link_to 'Edit', edit_runner_path(runner) %></td>
     <td><%= link_to 'Destroy', runner, confirm: 'Are you sure?', method: :delete %></td>
     </tr>
 <% end %>

into a file called _list_of_runners.html.erb
and replace it with

<% render ‘list_of_runners’ %>

It makes the index.html clearer, but clutters up the directory.

Back to associations:
One-to-Many
One movie has many actors:

class Movie < ActiveRecord::Base
     has_many :actors
 end
class Actor < ActiveRecord::Base
     belongs_to :movie
 end

User stories:
As a user, I want to see the list of teams in our softball league.
A team has a company name and a nickname.
As a user, I want to select a team, and see the list of players on the team.
A player has a name and a jersey number.

What about many-to-many?
Actors are in many movies, and movies have many actors.
There is the notion of a “Role” in between Movie and Actor. That joins them together.
Movie <-> Role <-> Actor
Movie has many roles, and an Actor can have many roles
Roles would have id, movie_id and actor_id

class Actor < ActiveRecord::Base
     has_many :roles
 end
class Role < ActiveRecord::Base

    belongs_to :movie

    belongs_to :actor
end

 

 

User <-> Review <-> Landmark

You just generate a model for a role
rails g scaffold Movie title:string year:integer
rails g scaffold Actor name:string
rails g model role movie_id: integer actor_id:integer character:string
Add the has_many and belongs_to statements

IN the console:
the hard way

Role.create :movie_id => 1, :actor_id => 1, :character_name =>’Lucky Day’
 amigos.roles
 r = amigos.roles.first
 r.movie
 r.actor
 r.actor.name

Another way to create a role

amigos.roles
 amigos.roles.create :actor_id => 2, :character => ‘Dusty Bottoms’
 mark = Actor.create :name => ‘Mark Hamill’
 star_wars.roles.create :actor => mark
 starwars.roles.create :actor => Actor.find_by_id(3), :name => “Leia”

Some stuff on migrations and controller filters
What about the salary for the role?
You cannot put it in the old migration file and re-run that
The timestamps are on there for a reason

You need to create a new migration for the new field
rails generate migration $NAME $FIELD:$TYPE
rails generate migration AddSalaryToRole salary:integer
It might generate the right thing. You would need this:

def change
     add_column :roles, :salary, :integer
 end

Then type rake db:migrate to make changes
rake db:version

Controller filters:
In the controller, we do

@movie Movie.find(params[:id])

quite a few times. (This would be better for something that is multiple lines.)
Make a method
def find_the_movie
It might generate the right thing.
end
You can call that when you need to
But there is still some repetition
If you want to call a method at the beginning of an action or method, that is a before filter
Put this at the top:

before_filter :find_the_movie

So even though destroy action has @movie in the first line, you won’t get an error since you get @movie from the filter
But index method does not get params[:id]. You will get an error
So how to run it only for certain actions

before_filter :find_the_movie, :only => [:show, :edit, :update, :destroy]

or to exclude some methods

before_filter :find_the_movie, :except => [:index, :new, :create]

DRY-ing code:
partials in views, pull them in with renders
controllers: use filters to extract common code

You can make your db lookups faster with indexes:

add_index :roles, :movie_id

You can put these in a migration
You probably want this for foreign keys

Image from Wikimedia, assumed allowed under Fair Use. Image from the Vatican Virgil, a 5th century manuscript of poems by Virgil.

Code Academy Week 3 Notes Post 02

2012-01-26_08.08.55 notes
Web requests: URL, method, format
In the routes.rb file, you can have the same URL, but different methods

If you are having trouble naming controllers, go into the Rails console, call the “pluarlize” or “singularize” methods. This will give you the Rails conventions.

In browsers, when you type something in the address bar it will automatically be an HTTP get request

Hashes

product = { :name => "iPad2", :price => 499, :quantity => 2 }
the_name = product[:name]
the_price = product[:price]
# change the name
product[:name] = "iPad3"

# you could have a hash inside a hash
params = {:shipping => :standard, :customer => {:name => "Patrick", :city => "Chicago" } }
# this will print out "standard" since we never put anything in that symbol
puts "Shipping: #{params[:standard]}"
customer_data = params[:customer]
puts "Name: #{customer_data[:name]}"
puts "City: #{cutomer_data[:city]}"
# or get a hash within a has
puts "City: #{params[:customer][:city]}"

Rails forms will have hashes and sub-hashes

3 parts to HTTP request: URL, method and format
The R is resources
Stop thinking pages, start thinking resources

1. web request
params hash contains the data
2. Rails App

3. Web response

Forms in Rails
use the form_for method.

<%= form_for @station do |f| %>
 <%= f.text_field :name %>

So you should see params[:station] with :station as a hash in the hash, and containing a key called :name

In the train station app, we could also do
Station.create params[:station]

How to change things in the database?
We use the HTTP method is PUT
We have to name our URLs in the routes.rb file

rake routes

The form knows to label button “Update Record”
In the rails console, you can call x.new_record?
Rails can support HTTP put method with a “_method” param with a value of “put”

To list methods well:

y Station.method.sort

y puts it in yaml
Cheating:

rails generate scaffold blog

TO get rid of it:

rails destroy scaffold blog

New is paired up with create, edit paired up with update conceptually, so pair them in your routes.rb file
In the update method of the controller, we could call @station.update_attributes(params[:station])

It is best to use named routes
If there is a URL with multiple HTTP methods, you only need to name them once
In the controllers, you use

redirect_to $ROUTE_NAME_url

If the path is stations:

redirect_to stations_url

But what if you need the ID?

redirect_to station_url(@station.id)

You could also do station_path
that will do the relative path
path gives you less data to the client
Only good if you will be in the same domain
Problem if you have a redirect

If you send an ActiveRecord object to a route in a link_to call, you could just send it @the_station instead of @the_station.id
The ID is the only one you could leave off. Everything else must be specified.

We will have a lot of controllers in a web app.
You will be creating, deleting, updating a lot of stuff
You could just do
resources :stations
There will be a cheat sheet for the routes

A lot of people never learn the long way like we did, they just learn the resources :model
Even Hartl does not go over that, which kind of surprises me.

Scaffold:
singular for model, plural for controllers, singular for scaffold
It will make a lot of stuff for you

rails generate scaffold station name:string address:string info:string

It creates something for a new station, as well as some edit, destroy, etc

rails generate scaffold Station name:string address:string info:string

and

rake db:migrate

afterwards
Scaffolding is not intended to be the final application
We will see that scaffolding will not do too much, especially when we have multiple models

Model validations: you will have rules about your models, aka business rules, or domain logic
don’t let a user sign up multiple times with same address, is credit card valid, etc, etc
These rules go in the model

class Movie < ActiveRecord::Base
     # this will make sure we have a title
     validates :title, :presence => true
 end

If you change model while in the rails console, you either need to exit or call reload!
Many of the variables will no longer be valid
You could call m.valid? and m.errors (which gives a hash)
or call: m.errors.full_messages
That returns an array

The scaffolding will create error handling as well

Image from Wikimedia, assumed allowed under Fair Use. Image from the Vatican Virgil, a 5th century manuscript of poems by Virgil.

Code Academy Week 3 Notes Post 01

2012-01-24_08.10.45

This week:
Arrays and blocks
MVC Recipe
CRUD your data
Rails resources
Model Associations

2 skills building: RoR coding and how to think about architecture of application

Arrays and blocks:
Arrays and collections

5.times do |n|
     puts "The Edens is ridiculous #{n + 1}"
 end

The times method will let you increment a block variable

Mate: command-control-shift-E will execute code

names = ["Marcel", "Chris", "Fabian", "Adam", "Jimmy"]

class Person
    attr_accessor :name
    # attr_accessor :favorite_color
    def favorite_color=(a_color)
        @favorite_color = a_color
    end
    def favorite_color
        return @favorite_color
    end
end

x = Person.new
x.name = "Marcel"
x.favorite_color = "Blue"
y = Person.new
y.name = "Chris"
y.favorite_color = "Red"
people = [x,y]

people.each do |person|
    puts person.name
    puts person.favorite_color
    puts "----"
end

# you could do names.length or name.size
names.each do |n|
    puts "#{n}"
end

 

Better way: Use .each method

MVC Recipe file is on Backpack – look it up and save it

Simple page demo:
display a list of train stations
1. Route definition
2. Controller class
3. Action method

1. Define a route that connects a url path to a controller and an action

MyApp::Application.routes.draw do
     get ‘stations’ => ‘stations#index’
 end

2. Write a controller class

# app/controllers/stations_controller.rb
class StationsController < ApplicationController

end

Follow conventions: Class is StationsController and file is stations_controller
3. Add an action method that generates your HTML

def index
     render :text => “<h1>Station List</h1>”
 end

Do not give your app the same name as one of your controllers
render method in the controller can take a file name, or :text => “Some text”

render :text => “<h1>I am awesome</h1>”

In response, you can give some HTML or redirect the user

redirect_to method “http://en.wikipedia.org/main/Illinois”
redirect_to “http://en.wikipedia.org/main/Illinois”

redirect will give a 302 http status code
In controller, either render some HTML or redirect

class StationsController < ApplicationController
     def index
         render :text => "<html>
        <body>
        <h1>Station List</h1>
         <ul>
         <li>Chicago</li>
         <li>Belmont</li>
        </ul>
         </body>
        </html>"
         # redirect_to "http://en.wikipedia.org/wiki/Illinois"
     end
end

 

But we could have nothing in the controller’s index method. Or we could put something in the views folder:
apps/views/$NAME_OF_CONTROLLER/$NAME_OF_ACTION.html

added an array @stations in the stations controller
Put this in the index.html.erb file:

<% @stations.each do |station|  %>
     <p>Name: <%= station %></p>
 <% end %>

You do not need to make an attr_accessor line in a controller to see it in the corresponding view. You can just use those variables in the view.

rails generate GENERATOR [args] [options]
 Usage: rails generate GENERATOR [args] [options]
General options:
 -h, [--help]     # Print generator's options and usage
 -p, [--pretend]  # Run but do not make any changes
 -f, [--force]    # Overwrite files that already exist
 -s, [--skip]     # Skip files that already exist
 -q, [--quiet]    # Suppress status output
Please choose a generator below.
Rails:
 assets
 controller
 generator
 helper
 integration_test
 mailer
 migration
 model
 observer
 performance_test
 plugin
 resource
 scaffold
 scaffold_controller
 session_migration
Coffee:
 coffee:assets
Jquery:
 jquery:install
Js:
 js:assets

 

For a model:

ca-imac1-2: ~/dev/tth/TrainStationApp$ rails generate model
Usage:
 rails generate model NAME [field:type field:type] [options]

Options:
     [--skip-namespace]  # Skip namespace (affects only isolated applications)
     [--old-style-hash]  # Force using old style hash (:foo => 'bar') on Ruby >= 1.9
 -o, --orm=NAME          # Orm to be invoked
                         # Default: active_record

ActiveRecord options:
     [--migration]            # Indicates when to generate migration
                              # Default: true
     [--timestamps]           # Indicates when to generate timestamps
                              # Default: true
     [--parent=PARENT]        # The parent class for the generated model
     [--indexes]              # Add indexes for references and belongs_to columns
                              # Default: true
 -t, [--test-framework=NAME]  # Test framework to be invoked
                              # Default: test_unit

TestUnit options:
     [--fixture]                   # Indicates when to generate fixture
                                   # Default: true
 -r, [--fixture-replacement=NAME]  # Fixture replacement to be invoked

Runtime options:
 -f, [--force]    # Overwrite files that already exist
 -p, [--pretend]  # Run but do not make any changes
 -q, [--quiet]    # Supress status output
 -s, [--skip]     # Skip files that already exist

Description:
   Create rails files for model generator.

Upgrade rails:
gem install rails --no-doc --no-ri
ca-imac1-2: ~/dev/tth/TrainStationApp$ gem install rails --no-rdoc --no-ri
Fetching: activesupport-3.2.0.gem (100%)
Fetching: activemodel-3.2.0.gem (100%)
Fetching: rack-1.4.1.gem (100%)
Fetching: journey-1.0.0.gem (100%)
Fetching: sprockets-2.1.2.gem (100%)
Fetching: actionpack-3.2.0.gem (100%)
Fetching: arel-3.0.0.gem (100%)
Fetching: activerecord-3.2.0.gem (100%)
Fetching: activeresource-3.2.0.gem (100%)
Fetching: mail-2.4.1.gem (100%)
Fetching: actionmailer-3.2.0.gem (100%)
Fetching: railties-3.2.0.gem (100%)
Fetching: rails-3.2.0.gem (100%)
Successfully installed activesupport-3.2.0
Successfully installed activemodel-3.2.0
Successfully installed rack-1.4.1
Successfully installed journey-1.0.0
Successfully installed sprockets-2.1.2
Successfully installed actionpack-3.2.0
Successfully installed arel-3.0.0
Successfully installed activerecord-3.2.0
Successfully installed activeresource-3.2.0
Successfully installed mail-2.4.1
Successfully installed actionmailer-3.2.0
Successfully installed railties-3.2.0
Successfully installed rails-3.2.0
13 gems installed

That was if you are using rvm
If not, you might need to use sudo

Models are singular, controllers are plural

ca-imac1-2: ~/dev/tth/TrainStationApp$ rails generate model station name:string address:string style:string
 invoke  active_record
 create    db/migrate/20120124163015_create_stations.rb
 create    app/models/station.rb
 invoke    test_unit
 create      test/unit/station_test.rb
 create      test/fixtures/stations.yml

Look at the migration file

class CreateStations < ActiveRecord::Migration
     def change
         create_table :stations do |t|
             t.string :name
             t.string :address
             t.string :style
             t.timestamps
         end
     end
 end

 

We can add columns before we do the migration
Migrations allow you to evolve your database. If you change your tables, add tables, etc

In model class, you start with a line like this:

class Station < ActiveRecord::Base

It will give you attr_accessor methods for the fields. Do not put them in.

To do the migration, do this:

rake db:migrate

To get  the version of the database.

rake db:version

To delete database:

rake db:drop

To drop database and start over fresh

rake db:migrate:reset

If you get errors, try “bundle exec” in front:

bundle exec rake db:migrate:reset

Some logs:

ca-imac1-2: ~/dev/tth/TrainStationApp$ rails console
 Loading development environment (Rails 3.1.3)
 1.9.3-p0 :001 > Station
 => Station(id: integer, name: string, address: string, style: string, created_at: datetime, updated_at: datetime)
 1.9.3-p0 :002 > x = Station.new
 => #<Station id: nil, name: nil, address: nil, style: nil, created_at: nil, updated_at: nil>
 1.9.3-p0 :003 > x.name='Chicago Ave'
 => "Chicago Ave"
 1.9.3-p0 :004 > x.style = 'Elevated'
 => "Elevated"
 1.9.3-p0 :005 > x.save
 SQL (4.8ms)  INSERT INTO "stations" ("address", "created_at", "name", "style", "updated_at") VALUES (?, ?, ?, ?, ?)  [["address", nil], ["created_at", Tue, 24 Jan 2012 16:44:13 UTC +00:00], ["name", "Chicago Ave"], ["style", "Elevated"], ["updated_at", Tue, 24 Jan 2012 16:44:13 UTC +00:00]]
 => true
Station.create :name => "Jackson", :style => "Subway"
 SQL (0.5ms)  INSERT INTO "stations" ("address", "created_at", "name", "style", "updated_at") VALUES (?, ?, ?, ?, ?)  [["address", nil], ["created_at", Tue, 24 Jan 2012 16:44:57 UTC +00:00], ["name", "Jackson"], ["style", "Subway"], ["updated_at", Tue, 24 Jan 2012 16:44:57 UTC +00:00]]

 

You could do Student.create!
This will throw an exception if something went wrong
We would need begin and rescue, and a rescue handler

So now in stations_controller, you can put the Station objects in a variable:

@all_stations = Stations.all

So put this in index:

<ul>
 <% @all_stations.each do |the_station|  %>
     <li>Name: <%= the_station.name %> which is <%= the_station.style %></li>
 <% end %>
 </ul>

He went over RailsGuides
Jeff prefers the Guides

Now let’s do something with one train station – the simplest way possible
Define a route that connects a URL path to a controller and action
In routes.rb:

get ‘stations/:id’ => ‘stations#show’

Add a controller action method

def show
     station_id = params[:id]
     @the_station = Station.find(station_id)
 end

You could also do Station.find_by_id(station_id)
Create an html.erb page for the action in app/views/stations

In controller: If we do find_by_id, we get a nil return value
if we do find, we get a better error message
We could handle errors in the application_controller class

In show, put in a link that goes back to the list:

<a href=”/stations”>

Or

<%=  link_to “List of stations”, “http://www.google.com” %>
 <%= link_to What_user_sees, where_link_goes %>
 <%=  link_to “List of stations”, “/stations” %>

In the list:

<ul>
<% @all_stations.each do |the_station|  %>
    <li>Name: <%= link_to the_station.name, "/stations/#{the_station.id}" %> which is <%= the_station.style %></li>
<% end %>
</ul>

Create a form so the user can enter something:
This would be the new action

<%= form_for @station do |f|  %>
     <p>
     <%= f.label :name %>
     <%= f.text_field :name %>
     </p>
 <% end %>

In form_for call, you provide the name of a model

The data we receive will come through the params hash
Recipe: route, controller, action, view

For the form:

get "stations/new" => "stations#new"

Put this one above the “stations/:id” route
In controller:

def new
     @station = Station.new
 end

Create a file app/views/stations/new.html.erb

To handle the form, put in another route

post “/stations” => “stations#create”

Create in controller:

def create
     form_data = params[:station]
     x = Station.new
     x.name = form_data[:name]
     x.save
     redirect_to "/stations"
 end

Here is the form:

<h1>Add a new station</h1>

<%= form_for @station do |form| %>
    <p> <%= form.label :name %> <%= form.text_field :name %> </p>
    <p> <%= form.label :style %> <%= form.text_field :style %> </p>
    <p> <%= form.label :address %> <%= form.text_field :address %> </p>
    <p><%=form.submit %> </p>
<% end %>

Returning JSON data

Example: Twitter

(BTW Brian Hogan)

There’s a URL you can use to get a JSON representation of someone’s twitter feed for instance.

Represents Objects in Text:

Some Common JSON Notation:

[ ] – array
{ } – hash
: – in between a key-value pair

in the index method of controller, use the respond_to method to specify what we could respond to

respond_to do |format|
     format.html # nothing else, Rails will look for template
     format.json { render :json => @all_stations }
 end

To request json from the browser:
http://localhost:3000/stations.json

also works for XML

respond_to do |format|
     format.html # nothing else, Rails will look for template
     format.xml  { render :xml => @all_stations }
     format.json { render :json => @all_stations }
 end

To request xml from the browser:
http://localhost:3000/stations.xml

To delete a station:
in show:

<p><%= link_to "Delete this station" "/stations/#{@the_station.id}", :method => :delete %></p>

So in routes:

delete "/stations/:id" => "stations#destroy"

So add a destroy method in controller

def destroy
     the_station_id = params[:id]
     @the_station = Station.find(the_station_id)
     @the_station.destroy
     redirect_to "/stations"
 end

Image from Wikimedia, assumed allowed under Fair Use. Image from the Vatican Virgil, a 5th century manuscript of poems by Virgil.