Code for Startup MVP (Ruby on Rails) Session 2

Post on 01-Sep-2014

1331 Views

Category:

Documents

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

Second Session on Learning to Code for Startup MVP's using Ruby on Rails.

Transcript

Learning to Code for Startup MVP

Presented by Henry Shi

Agenda – Wednesday November 7

1. Review of Last Session

2. Ruby Basicso Syntax and semanticso Practice makes perfect

3. Rails Models (but no Bottles)o ORM and SQL introductiono Migrationso Making the User modelo Signup/Signin/Signout

Prework – Setup

• Windows (not recommended if possible):o http://railsinstaller.org/o Use Sublime Text for your text editor

• OSX:o http://railsinstaller.org/o This includes osx-gcc-installer (200mb)

• Linux:o http://blog.sudobits.com/2012/05/02/how-to-install-rub

y-on-rails-in-ubuntu-12-04-lts/

Prework - Git

Install git if not already included:http://www.git-scm.com/book/en/Getting-Started-Installing-Git

Configure Git:git config --global user.name "Your Name“git config --global user.email

your.email@example.com

Review of Last Session

1. The Web and How it Works

2. Git/Github

3. Rails and Ruby

4. Heroku

The Web - Overview

GIT/GITHUB

• What is GIT?• Distributed Version Control System (DVCS)

• Why should I care?o Never lose data or accidentally overwrite, delete fileso Collaborate with peers anywhere and stay in sync

automatically (no more _v1, _v2, _final, _final_final…)o Compare and track changes over time, and easily

revert changeso Deploy code to real web

Rails

• Ruby on Rails is an open-source web framework that’s optimized for programmer happiness and sustainable productivity.

• It lets you write beautiful code by favoring convention over configuration.

• 80/20 Rule =>great for Startup MVP

Heroku

What is Heroku?• a hosted platform built specifically for

deploying Rails and other web applications in 1 command

• Best thing since sliced bread

Ruby – Programmer’s Best Friend

• Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.

• We will only cover the necessary syntax needed to create a rails app

• Thankfully, its not a lot

Interactive Ruby Shell

• For the following slides, you should follow along with the Interactive Ruby Shell (irb)

• Open a terminal, type irb and press enter

Ruby - Strings

• Characters (letters, digits, punctuation) surrounded by quotes

• Can perform operations on strings, concatenation, length, empty, etc

food = "chunky bacon"puts "I'm hungry for, #{food}!">> "I'm hungry for, chunky bacon!"

“Hello” + “World”>> “Hello World"“Henry”.empty?>> false

Ruby - Numbers

• Self Explanatory

• Can add different types of numbers directly

123.class>> Fixnum

(123.0).class>> Float

Ruby - Symbols

• Characters (letters, digits, punctuation) preceded by colon (:)

• Lightweight strings• immutable

food = :hello:asf3fasdf.class>> Symbol

Ruby - Array

• List surrounded by square brace and separated by commas, zero indexed

• Can perform operations on arrays, add, remove, reverse etc

a = [1, 2, 3]b = ('a'..'e').to_a # ["a", "b", "c", "d", "e"]c = %w[foo bar baz quux] # ["foo", "bar", "baz", "quux"]d = "foo bar baz".split # ["foo", "bar", "baz"]

a = a.reverse # [“world”, “hello”, 3, 2, 1]

a.push(“hello”) # [1, 2, 3, “hello”]a << “world” # [1, 2, 3, “hello”, “world”]

a[0] # 3

a.delete(“hello”) # [“world”, 3, 2, 1]

Ruby - Hash

• Hash is a dictionary surrounded by curly braces• Dictionaries match words with their definitions

• New (better) hash notation in Ruby 1.9+

• Important for passing optional params (can omit braces if hash is last argument)

my_var = {:sup => "dog", :foo => "bar"}my_var[:foo]>> "bar“my_var[:nk] = “new” # {foo : "bar“, nk: “new” , sup : "dog" }

{sup : "dog", foo : "bar"}.class #Ruby 1.9+ >> Hash

Ruby – Methods (Functions)

• Function that performs some operations when called and returns something when done

• Implicitly returns last expression in method• Use Ruby poetry style:

o a.should(be() >= 7) #bado a.should be >= 7

Ruby – Blocks

• Block of Code surrounded by curly braces

• Can use Do and end to indicate block as well

• Can take argumentso variables surrounded by pipe (|)

2.times { puts "hello"}>> "hello">> "hello"

2.times do puts "hello“end

2.times do |i| puts "hello {#i}”end>> "hello 0">> "hello 1"

Ruby – Blocks (Advanced Only)

• Blocks are closures: they carry their environment around with them

• Block are anonymous λ functions• Examples compared to scheme:

o (map '(lambda (x) (+ x 2)) mylist )

o mylist.map { |x| x+2 }

• Try this: ('a'..'z').to_a.shuffle[0..7].join

(map'(lambda (x) (+ x 2))

(filter '(lambda (x) (even? x)) mylist))

mylist.select {|x| x.even?}.map {|x| x+2 }

Ruby – Blocks, Methods, Hashes

def list_hash(options = {:default => "foo"})options.each do |key, value|

puts "key '#{key}' points to '#{value}'"end

end

list_hash override : "bar")>> "key 'override' points to 'bar'"

list_hash multiple : "values", can : "be_passed")

>> "key 'multiple' points to 'values'"

>> "key 'can' points to 'be_passed'"

Ruby – Hashes in Rails

• Used heavily as parameters

Ruby – Classes and Objects

• Ruby, like many object-oriented languages, uses classes to organize methods; these classes are then instantiated to create objects

Ruby – Classes and Objects

• Most common uses will be in Models and Controllers

• attribute accessors (attr_accessor) corresponding to a user’s name and email address.

• This creates “getter” and “setter” methods that allow us to retrieve (get) and assign (set) @name and @email instance variables

Ruby Class and Object Example

• Save the above code into a file called example_user.rb• Run the following in irb

Ruby – Classes and Objects (Advanced Only)class SavingsAccount < Account # inheritance

# constructor used when SavingsAccount.new(...) calleddef initialize(starting_balance=0) # optional argument@balance = starting_balance

enddef balance # instance method

@balance # instance var: visible only to this objectenddef balance=(new_amount) # note method name: like setter

@balance = new_amountend

def deposit(amount)@balance += amount

end@@bank_name = "MyBank.com" # class (static) variable# A class methoddef self.bank_name # note difference in method def@@bank_name

end# or: def SavingsAccount.bank_name ; @@bank_name ; end

end

Ruby – Objects and Method Calls (Advanced Only)

1.send(:+, 2)my_array.send(:[], 4)my_array.send(:[]=, 3,"foo")if (x.send(:==, 3)) ...self.send(:my_func, z)

•  Even lowly integers and nil are true objects:57.methods

57.heinz_varietiesnil.respond_to?(:to_s) "

•  Rewrite each of these as calls to send:"–  Example: my_str.length => my_str.send(:length)1 + 2

my_array[4]my_array[3] = "foo"if (x == 3) ....my_func(z)

•  When you are calling a method, you are actually sendinga method call to the receiver object, which responds

Ruby – Method Calls (Advanced Only)

yy

= [1,2] = y + ["foo",:bar] # => [1,2,"foo",:bar]

yy

<< 5<< [6,7]

# => [1,2,"foo",:bar,5] # => [1,2,"foo",:bar,5,[6,7]]

•  Remember! These are nearly all instance methods of Array—not language operators!"

•  So 5+3, "a"+"b", and [a,b]+[b,c] are all differentmethods named '+'"–  Numeric#+, String#+, and Array#+, to be specific"

•  Every operation is a method call

•  a.b means: call method b on object a– a is the receiver to which you send the method call,

assuming a will respond to that method"

Ruby – Practice

• Tryruby.org (code in ruby on your browser and work through free exercises)

• Read Section 4.1 to 4.5 of Ruby on Rails Tutorial by Michael Hartl

Rails - Models

We will focus on Models in this section

But First, we must understand the underlying datastore that actually stores the data

Databases, Tables, SQL

Rails – Database backed Models

• Store and access massive amounts of data• Table

o Columns (name, type, modifier)o Rows

Table:Users

SQL

• Structured Query Languageo A way to talk to databases

• Operations (CRUD)o Createo Read (Query)o Updateo Deleteo Schema creation and modification

SELECT *FROM BookWHERE price > 100.00ORDER BY title;

Rails – Object Relational Mapping

• Maps database backend to ruby objects• ActiveRecord (Rail’s Default ORM)

>> userVariable = User.where(name: "Bob")

>> userVariable.name=> Bob

Generates:SELECTWHERE

"users".* FROM "users"(name = 'bob')

Rails – Object Relational Mapping

>> userVariable = User.where(name: "Bob")

• Plural of Model name is table name (User -> users)

• Subclassing from ActiveRecord::Base “Connects” a model to the databaseo Provides CRUD operations on the modelo Database table column names are getters & setters for model

attributeso Model attributes automagically defined from the database table

columns

models/user.rbclass User < ActiveRecord::Base attr_accesor :name, :emailend

Rails – Creating Users

• We could start from scratch and create all aspects of the Users models from scratch, but that wouldn’t be in the philosophy of an MVP

• What additional functions might a user model need?o Registrationo Log in/Log out (sessions)o Reset/Lost Passwordo Email confirmationso Invitations to friends

Rails – Creating Users - Devise

• We will use the awesome Gem: Devise• Gems are packages/libraries for your rails project• Before coding, always see if a gem exists at The Rails Toolbox

Rails - Devise

• Create a new rails appo rails new MiniTwitter

• Open Gemfile (from last class)

• Add the line:Gem ‘devise’, ‘2.1.0’

• Run Bundle install from the console

• Install Devise by typing in the console: rails generate devise:install

• Generate the user by typing in the console:rails generate devise User

• Run the migration by typing in the console:Bundle exec rake db:migrate

Rails – Devise

• You may seem some hints/warnings:

Rails – Devise

• Go to http://localhost:3000/users/sign_up to see Devise in action!

• Sign up a fake user account and now try to log in at http://localhost:3000/users/sign_in

• Rails never shows or stores passwords in plaintext

Rails – Devise

• What did we just do?o rails generate devise User

o Focus on Migration and User Model

Rails – Migrations

• Create data structure in your database• Set a database’s schema incrementally

o Consistent across multiple machines (no conflicts)o Easy to upgrade, rollback, track changes, etc

• Migration is automatically created every time you create a model

• Open db/migrate/[timestamp]_devise_create_users.rb

Rails – Migrations• Creates a table named

Users

• Adds Columns:o Emailo Encrypted_passwordo Etc, etco T.timestamps creates the

columns created_at and updated_at autmagically

o Can pass parameters to columns, default values, nullable, etc

• Adds Indices:o Ensures uniquenesso Faster searchingo Index on email

Rails – Migrations

• Active Record Maps ruby objects to database• User.email

Rails – Migrations

• Database looks like:

• Same as what was specified in the migration

Rails – Migrations

• Run a migration

• Rollback (undo) a migration

>> bundle exec rake db:migrate

>> bundle exec rake db:rollback

Rails – Migrationsrails generate migration AddNameToUsers name:string

• Creates a migration automagically on the users table because we followed naming conventionso AddXXXToYYY followed by column name and type

• More info: http://guides.rubyonrails.org/migrations.html

Rails – Models

• Open app/models/user.rb

• Attr_accessible is important for preventing mass assignment vulnerability

• Notice we don’t have any attributes explicitly defined from the database (ORM maps attributes implicitly in Rails’ Activerecord)o Can remind ourselves of the database columns using ‘annotate’ gem

Rails – Attributes

• Open app/models/user.rb

• Can add methods to the user modeldef unchanged_duration

updated_at – Time.now

end- Duration in which the user was not modified

Rails – Models- Validations

• Check your parameters before save• Provided by ActiveModel

class Person < ActiveRecord::Basevalidates :title, :presence => true

end

bob = Person.create(title: nil)>> bob.valid?=> false>> bob.save=> false

Rails – Models- Validations

• Rails’ built in validation

• Can also write your own validations

:acceptance => Boolean.:confirmation => Boolean.:exclusion => { :in => Enumerable }.:inclusion => { :in => Enumerable }.:format => { :with => Regexp, :on => :create }.:length => { :maximum => Fixnum }.:numericality => Boolean.:presence => Boolean.:uniqueness => Boolean.

class User < ActiveRecord::Basevalidate :my_custom_validationprivate

def my_custom_validationself.errors.add(:coolness, "bad") unless self.cool ==

“supercool”end

end

Rails – Models and Migrations Exercises

• Create a migration to add first_name and last_name to the User table

• Add validation for user’s email, first_name and last_name such that they must be present

• Make a method full_name on user object to retrieve user’s full name by concatenating first and last name

Rails - Models

• Further ReadingRuby on Rails Tutorial – Michael HartlSection 6.1 – 6.2 (6.3 optional)

Git Commit

git initgit add .git commit –m “Initial Commit of MiniTwitter”(optional) git remote add origin

git@github.com:<username>/first_app.git(optional)git push –u origin master

Heroku – New MiniTwitter App

• Sign up for Heroku (it’s Free!) http://api.heroku.com/signup

• Install the Heroku Toolbelt https://toolbelt.heroku.com/

• Heroku login• Heroku create

o This will create a heroku app and tell you the url of your app

• Git push heroku mastero This’ll deploy your code to Heroku. Let it do its magic!

• Heroku run rake db:migrate• Heroku open

Next Time…

• Exploring Rails deeper• More about Controllers and Views• Building toward our Twitter app posts, friends,

followers, feeds, etc• Stay Tuned….

• Thanks!

Rails - Appendix

• If we have time…

Rails – Models - Create

•  Must call save or save! on an AR modelinstance to actually save changes to DB"– '!' version is “dangerous”: throws exception ifoperation fails"

– create just combines new and save

•  Once created, object acquires a primary key(id column in every AR model table)"– if x.id is nil or x.new_record? is true, xhas never been saved"– These behaviors inherited from ActiveRecord::Base—not true of Ruby objects in general"

Rails – Models - Read

•  Class method where selects objects based onattributes

Movie.where("rating='PG’)Movie.where('release_date < :cutoff and

rating = :rating',:rating => 'PG', :cutoff => 1.year.ago)

Movie.where("rating=#{rating}") # BAD IDEA!•  Can be chained together efficiently

kiddie = Movie.where("rating='G')

old_kids_films =kiddie.where "release_date < ?",

30.years.ago

Rails – Models - Read

Movie.find(3) #exception if not foundMovie.find_by_id(3) # nil if not found

•  Dynamic attribute-based finders using

Movie.find_all_by_rating('PG')Movie.find_by_rating('PG')Movie.find_by_rating!('PG')

• Find Models by id

Rails – Models - Delete

•  Note! destroy is an instance methodm = Movie.find_by_name('The Help')m.destroy

•  Thereʼs also delete, which doesnʼt triggerlifecycle callbacks weʼll discuss later (so,avoid it)"

•  Once an AR object is destroyed, you canaccess but not modify in-memory object

m.title = 'Help'

top related