learning to code for startup mvp session 3
TRANSCRIPT
Learning to Code for Startup MVP
Presented by Henry Shi
Agenda – Monday November 26
1. Review of Last Session
2. Rails Controllers
3. Rails Router
4. Rails View and Frontend
5. Followers + Relationships
6. To be Continued… (Interface, Feed)
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 [email protected]
Review of Last Session
1. The Web and How it Works
2. Ruby Basics
3. Rails Models
4. Authentication and User accounts
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 – 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 – Database backed Models
• Store and access massive amounts of data
• Tableo Columns (name, type, modifier)o Rows
Table:User
s
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.rb
class User < ActiveRecord::Base attr_accesor :name, :emailend
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
Git Commit
git init
git add .
git commit –m “Initial Commit of MiniTwitter”
(optional) git remote add origin [email protected]:<username>/first_app.git
(optional)git push –u origin master
Rails MVC – Quick Review
• Model: methods to get/manipulate data“ /app/models/post.rbPost.where(...), Post.find(...)
• Controller: get data from Model, make available to View /app/controllers/posts_controller.rb
def show @movie = Post.find(params[:id])
end
• View: display data, allow user interaction“ /app/views/users/*.html.erb
– Show details of a Post (description, timestamp, etc)
Rails Controllers - Variables
• Some housekeeping knowledge (you’ll see this a lot in controllers)
foobar
@foobar
@@foobar
$foobar
FOOBAR
FooBar
# local variable
# instance variable, starts with @
# class variable, starts with @@
# global variable, starts with $
# Constant, starts with a capital letter
# Classes are constants
Rails Controllers - Intro
• Handles Business Logic
• Pass Data to Controller via Query String
class PostsController <
ApplicationControllerdef newend
end
http://localhost:3000/posts/new
http://localhost:3000/posts?status=posted
?status=published
?status=published&language=english
Rails Controllers - Params
• Params (hash) – get data from url
• Instance variables – pass data to view
def index
@status = params[:status]
if @status == “published"@clients = Post.published
else
@clients = Post.removed
endend
http://localhost:3000/posts?status=published
Rails Controllers – Params Hash
• Receive Hashes from Formso Great for handling data and user input
Hash
Form
{name: “Acme”, phone: “12345”, address: {postcode: “12345”}}
<form action="/clients" method="post"><input type="text" name="client[name]" value="Acme" /><input type="text" name="client[phone]" value="12345" /><input type="text" name="client[address][postcode]" value="12345" />
</form>
params[:client] # =>
<- Notice the nested hash (corresponding to nested form)
Rails Controller – Application Flow
• Can redirect to another action/url
• Rails automatically creates
names for url routes (more later)
# send to another action/urlIf not_logged_in redirect_to "/home”else if not_authorized redirect_to help_pathelse @post = Post.newend
http://localhost:3000/posts/new
Rails Controller - Rendering
• Passes instance variables and data to view to render to end user
• If don’t call render, Rails will default to view named action_name.html.erb in the controller’s view path and render it
• Lots of more info here: http://guides.rubyonrails.org/layouts_and_rendering.html
# Various rendering options
render “some_template"render layout: "awesome"render text : "foo"render json: @postrender xml: @postrender status: forbiddenrender file: filename,,content_type: ‘application/rss’'
Rails Router – Overview1. Routes (in routes.rb) map incoming URLʼs to controlleractions and extract any optional parameters!
– Routeʼs “wildcard” parameters (eg :id), plus any stuff after “?” in URL,are put into params[] hash accessible in controller actions"
2. Controller actions set instance variables, visible to views"– Subdirs and filenames of views/ match controllers & action names"
3. Controller action eventually renders a view"
app/controllers/movies_controller.rb
def showid = params[:id]@mv=Movie.find(id)
end
app/views/movies/show.html.haml
<li>Rating:= @mv.rating
GET /movies/:id{:action=>'show',:controller=>'movies'}
config/routes.rb
Rails Router
• Handles what controller & action pair to call for given url
• Config/routes.rb is the main router file for the entire application
o Visiting /about will call static_pagers#contact method
• Can view current route setups by running:o Rake routes (in shell console)
Rails Router - REST
• REsprentational State Transfer (REST)o Way of modelling resources and keeping consistent
urls across the web – after Roy Fieldings PhD Dissertation
• Main Features:1. Resources (Nouns) addressable through URL
2. Standard Methods (Verb)o GET, POSTo PUT, DELETE
Rails Router - REST
• Rails maps HTTP Methods to Controller Actionso GET -> index, show, newo POST -> createo PUT -> updateo DELETE -> destroy
Rails Router - Resources
• Can automatically specify resources in routes.rb and Rails will create 7 url mappings
routes.rbresources: Photo Method name in photos_controller.rb
When you visit, localhost:3000/photos/2 (GET request), Rails will call PhotosController#show and will pass Params[:id] = 2
Passed to params hash
Rails Router – Helper Paths
• Creating a resource in routes.rb also automatically creates helper paths:
• photos_path #=>returns /photos
• new_photo_path #=>returns /photos/new
• edit_photo_path(:id) #=>returns /photos/:id/edit
• photo_path(:id) returns #=>/photos/:id
Note:
_path returns relative url (eg. /photos)
_url returns absolute url (eg. www.myrailsapp.com/photos)
Rails Router – Nested Resources
• Can Nest resources to model relationships
Many more powerful routing options available:
http://guides.rubyonrails.org/routing.html
Rails Controller – Mini Twitter
• Use Scaffolding to create a Post model and controller
• Make Posts a nested resource of Users in the router
• Modify the PostsController to display all the posts of a given user when visiting/user/:id/posts
Mini Twitter – Posts Model
rails generate scaffold Post content:string user_id:integero Use rails scaffolding to generate posts!
bundle exec rake db:migrate
Edit: app/models/post.rb
Rails so Submitting a post with more than 140 chars will give
error (Automatically handled by Rails!)
Mini Twitter – Post Route
• Routes.rb:
• rake routes (to view available routes)
Mini Twitter – Post Controller
• App/controllers/post_controllers.rb:
• Visiting /users/:id/posts will return all the posts by the given user
• Correction: should be find_all_by_user_id
Rails Controller - Summary
• To add a new action, can use scaffoldingo rails g scaffold Model_Name type:Attribute…
Or:
1. Create route in config/routes.rb if needed"
2. Add the action (method) in the appropriateapp/controllers/*_controller.rb!
3. Ensure there is something for the action torender in app/views/model/action.html.erb!
Rails Views
• Views are what ends up being displayed in the user’s browser
• Separation of controls:o presentation (views) vs business logic (controller)o Usually involves the controller placing dynamically
generated data into a template and then rendering the template into the final HTML file
• We’ll use the default ERB templating systemo Many other templating systems (haml, liquid, etc)
Rails Views - ERB
• Embedded Ruby (part of Ruby standard lib)
• Ruby code that generates HTML
• <%= expression %>o Substitute code element with result of the code (as string)
• <% scriptlet %>o Executed, and most commonly used for loops/logic
<h1>People</h1><ul>
<h1>People</h1><ul><li>Bob</li>
<li>Joe</li><li>Mary</
li></ul>
<% @people.each do |person| %><li><%= person.first_name
%></li><% end %>
</ul>
Rails Views - Forms
• Forms allow user to input and submit data
• for_for helper in Rails
Rails View - Form
• Generated HTML
Rails View – CSS, Sass
• CSS used to provide styling to HTML (not look ugly), but CSS is ugly to write
• Sass is an extension of CSS3, adding nested rules, variables,mixins, selector inheritance, and more
• Rails’ asset pipeline supports Sass and compiles it to CSS
Rails Views – Bootstrap
• CSS framework for rapid prototyping
• Make sites look non-sh***y
• Responsive design and support cross platform devices
Before After (with Bootstrap)
Rails Views – Install Bootstrap
• Download Bootstrap CSS:o http://twitter.github.com/bootstrap/assets/bootstrap.zip
• Copy bootstrap.min.css and bootstrap.min.css to /vendor/assets/stylesheets
• Copy bootstrap.min.js to /vendor/assets/javascripts
• Copy images to app/assets/images
• Edit: app/assets/stylesheets/application.csso Add: *= require bootstrap.min to third last line
• Edit: app/assets/javascripts/application.jso Add: *= require bootstrap.min to third last line
• The last 2 lines tells the Rails asset pipeline to include the bootstrap css and js files when compiling all the assets
Rails Views - Exercise
• Modify Post views so that User’s email is displayed instead of user_id
• App/views/posts/show.html.erb
Rails - Associations
• One of Rail’s most powerful features is ability to form associations between data model
• each user potentially has many microposts
• Edit: app/models/user.rb
• Edit: app/models/post.rb
Rails - Associations
• Primary Keyo Unique identifier for all objects
• Foreign Keyo Relates to another row’s primary key
Hats:
id: 557
style: "Fedora"
Hats:
id: 687
style: "Cowboy"
Hatsid: 557style: "Fedora"inspector_id: 35
Inspectorsid: 35name: "John"
Rails - Relationships
• Relationships through foreign and primary keys
Rails – Models and Relationships
• Association is a connection between two Active Record models
• Types of Associations:o belongs_too has_oneo has_manyo has_many :througho has_one :througho has_and_belongs_to_many
Rails – Belongs To
• belongs_to :parent_classo Sets foreign key to match primary key
• Convention is parent_id is foreign_key field in child class
Rails – Has Many
• has_many :child_class (plural)o Builds Association in Rails
• Related objects contain links to one another
• Can get object’s associated objects>> myCustomer = Customer.where(:id => 2)>> orders = myCustomer.orders
Rails – Has Many Through
• Question? What if Patient has many Physicians and Physician has many Patients?
• Need many-to-many connection via 3rd model
Rails – Has Many and Belongs to Many
• Creates direct many to many relationship (via implicit 3rd model)
• Still need to create assemblies_parts in db via migration!
Rails – Followers and Following
• Many-Many relationship between Users and Users!
• Relationships is the 3rd model needed for the many-many relationship
Rails – Relationship Model
• Generate relationship model:
• Add indices for faster queries
• Run migration:
Rails – Relationship
• Add belongs_to in app/models/relationship.rb
• Can now call relationship.follower to get the follower (User) in the relationship
• Same for followed
Rails – Followed User
• Add has_many association in app/models/user.rb
• User.followed_users looks up the relationship objects via matching the follower_id to the User’s id, and return the list of followed Users in the relationships (which correspond to the User’s followed users)
Rails – Followed User
• Adding some utility methods to the User model
Checks if the user is following the other user by seeing if the relationship object exists
Creates a relationship to indicate that the user is now following the other user
Rails – Followers
• Add has_many association in app/models/user.rb
• User.followers looks up the relationship objects via matching the followed_id to the User’s id, and return the list of follower in the relationships (which correspond to the User’s followers)
Relationships already exists for followed users, so need another name to indicate “reverse relationship” for followers
Rails - Followers
• We now have all the backend needed to implement followers and following
Rails – Feed (User)
• Create method to get posts from all followed Users in app/models/user.rb
• Need to implement from_users_followed_by method in the Post model
Rails – Feed (Post)
• Create from_users_followed_by method in the Post model
• Select all the posts where the user_id matches any one of the user_id’s in the followed_user_ids list or equals the original owner user’s id
Rails – Feed (Users) Optimization
• Previously, stored array of user’s followed_user_ids in memory
• Optimize by using subquery and offload to DB
• But even this won’t scale forevero May need to generate the feed asynchronously using
a background job
Rails - Feed
• We now have all the backend needed to implement the feed
Rails - Feeds
• Further Reading
Ruby on Rails Tutorial – Michael Hartl
Section 11
Git Commit
git init
git add .
git commit –m “Added followers, following and feed of MiniTwitter”
(optional) git remote add origin [email protected]:<username>/MiniTwitter.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 createo 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…
• Building the front-end for followers and feed
• Implementing Ajax for follow button
• More to come...
• Stayed tuned for next term!
Thanks!
• It was a pleasure to create this course and present. I enjoyed every minute of it.
• Hopefully you were able to learn something useful and will look to using Rails in your next project!
• If these sessions helped you, please leave a positive note or testimonial
Resources
• Questions? I’d be glad to help
• henrythe9th at gmail dot com
• @henrythe9ths
• Agile Web Development with Rails—Fourth Edition
• Programming Ruby: The Pragmatic Programmers' Guide – Third Edition
• RailsCasts
• Rails main site http://www.rubyonrails.com
• CodeSchool
• Peepcode