Ruby Announcements

They are not announcements about Ruby in general, just about me.

First off, I submitted two proposals to speak at Lone Star Ruby Conf in Austin, Texas in August. One was accepted, and one was rejected. I started work on my presentation. I may also start the other presentation later at some point.

Also: The RSpec Study Group that I keep talking about is finally getting off the ground. The first day will be July 9th. Expect more details soon. It may be known at the Chicago Ruby Testing Group, since we will talk about more than just RSpec. We will still focus on Ruby testing technologies, so Python, PHP, dot NET and Java people will be out of luck. I am working on this with another Code Academy alum, with some help from a couple of Code Academy mentors.

Image from an 11th century manuscript housed at Bavarian State Library, webpage information here, image from World Document Library, image assumed allowed under Fair Use.

 

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.

Update on RSpec TDD Study Group

We had the first (informal) meeting of the RSpec study group. Three other guys showed up. All three plan on being mentors at Code Academy.

The plan is to mix lectures and “labs”. One of them had introduced RSpec/TDD to people while pairing with them, and felt it was a good experience. I thought we should mix in some lectures since there is probably more to RSpec than the

something.should_have something_else

stuff we saw in the famous Hartl tutorial. So we will go over a few chapters in The RSpec Book first before setting up a formal schedule. We will probably cover some Cucumber and Capybara as well.

I mentioned during the Code Academy Demo Day that I was planning on starting an RSpec study group. One of the people in the audience was Bobby Norton, who spoke at CJUG about a week before. He told me I should talk to David Chelimsky. He is here in Chicago, is a contributor to RSpec and one of the co-authors of the RSpec book. Looking at his Github profile, I now realize that I had seen him around at events quite a few times. In all of the Chicago Ruby meetups and other events I had gone to, nobody ever told me who he was or that a giant walked amongst us.

I hope he doesn’t think I’m a jerk.

Last thought: Agile shops say you should program “Tests -first.” Should languages be taught  “Testing frameworks-first”?

Image from Wikimedia, assumed allowed under Fair Use. Image from the St Augustine Gospels, a 6th century manuscript made in Italy in the 6th century, brought to Britain by the Other Saint Ausgustine.

 

What Happens After Code Academy?

What happens after Code Academy?

At this point, I have no idea.

The goal is to get a job, perhaps an apprenticeship that leads to a job.

Right now I am trying to nail down my living situation. I have to find some storage for my stuff. Granted, if I am putting stuff in storage that means I probably need to get rid of some stuff.

I may go to Rails Conf.  First I have to get depressed about the hole it will put in my savings.

I am also trying to get an RSpec study group started here in Chicago. I could start building apps right and left, but I would like to do it the right way, with TDD and BDD.

As far as jobs, I would like to get a Ruby/Rails job. I just spent a lot of time learning it. I am not too thrilled with Java these days. There are too many web frameworks that are awkward to test and develop with. There are a lot of companies using old versions of these frameworks as well. There are too many ways to do concurrency. I think over time the Akka library will push a lot of stuff aside.

Sidebar: Why didn’t Sun just use Actors for concurrency in Java from the beginning? Or add them later instead of adding another concurrency API for every other version of the JDK? It is interesting that this is so convoluted in Java and there are so many ways to do it, yet when you talk to the Erlang people, they say, “We just use Actors.” And they have been happy with that for more than twenty years.

I was talking several months ago to someone at Groupon about threading and concurrency in Rails and Ruby. He said that those are things that they do not really worry too much about. He said, “Come to the dark side. We have cake.” That started my journey to Ruby and Rails.

Image from Wikimedia, assumed allowed under Fair Use. Image from the Garima Gospels, an Ethiopian Gospel manuscript created around 500 AD. It is believed to be the oldest complete Gospel manuscript.

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 5 and Week 6

I am behind in posting weekly about Code Academy.

You can see the notes for weeks 5 and 6 for what we did. I also met my mentor at 8th Light.

The big thing over the past couple of weeks was Startup Weekend. There were no actual startups involved. The idea was to get four or five groups of Code Academy students together and make some apps in a weekend.

There were about 40 of us there. People gave ideas for applications, we all voted on them, and the top five ideas were not picked. Then people decided which app they wanted to be a part of.

The team that I am on was there all weekend. I think I stayed up all night Saturday night. On Sunday afternoon we all presented our apps to the group. I think it is a testament to the power of Rails that beginners could whip up some working apps in a weekend. This was almost two weeks ago. We were getting dinner on Saturday when I found out that Whitney Houston had died.

Our team decided to keep working on our app. We got together last weekend with the brother of one team member. The brother helped walked us through some agile methodologies to work on our requirements. We wrote the needs for different types of users on the whiteboard. Then we came up with features that would meet those needs. Then we prioritized them into “Must Have”, “Nice To Have”, “Later”, and I think the last one was “Who Cares?”

So we will probably get together in a few days to work on it some more. We pushed what we did on startup weekend to Heroku, and we started a github account for our app.

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