Sample App



$ rails new sample_app --skip-test-unit               # not to generate a test directory

include gems: RSpec for testing purposes, We also include the Capybara gem, which allows us to simulate a user’s interaction with the sample application using a natural English-like syntax, together with Selenium, one of Capybara’s dependencies.
$ vim ./Gemfile
gem 'rspec-rails', '2.13.1'
 
group :test do
  gem 'selenium-webdriver', '2.0.0'
  gem 'capybara', '2.1.0'
end

$ bundle install
$ bundle update
$ bundle install
group :production do gem 'pg', '0.15.1' gem 'rails_12factor', '0.0.2' end
$ bundle install --without production  
we suppress the installation of production gems using the option --without production. This is a “remembered option”, which means that we don’t have to include it in future invocations of Bundler. Instead, we can write simply bundle install and production gems will be ignored automatically.
configure Rails to use RSpec in place of Test::Unit.
$ rails generate rspec:install

Configure gith(hub) integration
$ git init $ git add . $ git commit -m "Initial commit"

create github repository https://github.com/new

$ git remote add origin https://github.com/<username>/sample_app.git
$ git push -u origin master

$ git checkout -b static-pages
$ git push --all

$ rails generate controller StaticPages home help --no-test-framework           # suppress the generation of the default RSpec tests
      create  app/controllers/static_pages_controller.rb
       route  get "static_pages/help"
       route  get "static_pages/home"
      invoke  erb
      create    app/views/static_pages
      create    app/views/static_pages/home.html.erb
      create    app/views/static_pages/help.html.erb
      invoke  helper
      create    app/helpers/static_pages_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/static_pages.js.coffee
      invoke    scss
      create      app/assets/stylesheets/static_pages.css.scss


we have passed the controller name as so-called CamelCase, which leads to the creation of a controller file written in snake case, so that a controller called StaticPages yields a file called static_pages_controller.rb. using snake case at the command line also works: the command  $ rails generate controller static_pages also generates a controller called static_pages_controller.rb.
Because Ruby uses CamelCase for class names, my preference is to refer to controllers using their CamelCase names, but this is a matter of taste. (Since Ruby filenames typically use snake case, the Rails generator converts CamelCase to snake case using the underscore method.)

Look into ./config/routes.rb
get "static_pages/home"
maps requests for the URL /static_pages/home to the home action in the StaticPages controller. Moreover, by using get we arrange for the route to respond to a GET request, which is one of the fundamental HTTP verbs supported by the hypertext transfer protocol (Box 3.3). In our case, this means that when we generate a home action inside the StaticPages controller we automatically get a page at the address /static_pages/home.

PATCH and DELETE, are designed for updating and destroying things on the remote server. These requests are less common than GET and POST since browsers are incapable of sending them natively, but some web frameworks (including Ruby on Rails) have clever ways of making it seem like browsers are issuing such requests.

http://localhost:3000/static_pages/home

$ vim ./app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end
end

Note that, unlike the demo Users and Microposts controllers, the StaticPages controller does not use the standard REST actions. This is normal for a collection of static pages—the REST architecture isn’t the best solution to every problem.

 when visiting the URL /static_pages/home, Rails looks in the StaticPages controller and executes the code in the home action, and then renders the view. the home action here is empty, so all visiting /static_pages/home does is render the view.


Notice the correspondence between actions and views. (home/help) ==> (home.html.erb/help.html.erb)




Apply Test Cases

$ rails generate integration_test static_pages
      invoke  rspec
      create    spec/requests/static_pages_spec.rb

$ vim ./spec/requests/static_pages_spec.rb
require 'spec_helper'

describe "StaticPages" do

  describe "Home page" do  # The first line indicates that we are describing the Home page.
    # This description is just a string and is not important.


    it "should have the content 'Sample App'" do    # describing string
      visit '/static_pages/home'                    #  simulate visiting the URL /static_pages/home in a browser
      expect(page).to have_content('Sample App')  # when you visit the Home page at /static_pages/home, the content should contain the words “Sample App”
    end
  end
end

# What goes inside the quote marks is irrelevant to RSpec, and is intended to be descriptive to human readers.

$ vim ./spec/spec_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
.
.
.
RSpec.configure do |config|
  .
  .
  .
  config.include Capybara::DSL
end
$ bundle exec rspec spec/requests/static_pages_spec.rb     # run the failing test case

To  pass the test

$ vim  app/views/static_pages/home.html.erb
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
  sample application.
</p>

About Page Test Driven Development

first create the testcase
    $ vim ./spec/requests/static_pages_spec.rb
 describe "About page" do

    it "should have the content 'About Us'" do
      visit '/static_pages/about'
      expect(page).to have_content('About Us')
    end
  end
$ bundle exec rspec spec/requests/static_pages_spec.rb       # see the test failing
Error is No route matches [GET] "/static_pages/about"
This is a hint that we need to add /static_pages/about to the routes file,
    $ vim config/routes.rb
  get "static_pages/about"
$ bundle exec rspec spec/requests/static_pages_spec.rb      
Error is The action 'about' could not be found for StaticPagesController

    $ vim app/controllers/static_pages_controller.rb
 def about          # Add about action
  end
$ bundle exec rspec spec/requests/static_pages_spec.rb       
Error is Missing template static_pages/about, application/about with ...

$ vim  app/views/static_pages/about.html.erb 
<h1>About Us</h1>
<p>
  The <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
  is a project to make a book and screencasts to teach web development
  with <a href="http://rubyonrails.org/">Ruby on Rails</a>. This
  is the sample application for the tutorial.
</p>
$ bundle exec rspec spec/requests/static_pages_spec.rb       
Test passed


Add dynamic content to static pages

Currently the title of all the pages are SampleApp, we want each page to have its own title.
$ git mv ./app/views/layouts/application.html.erb   foobar       # disable layout

$ vim ./spec/requests/static_pages_spec.rb
  it "should have the right title" do
      visit '/static_pages/home'
      expect(page).to have_title("Ruby on Rails Tutorial Sample App | Home")
    end

$ bundle exec rspec spec/requests/static_pages_spec.rb   #fail
$ vim ./app/views/static_pages/home.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Ruby on Rails Tutorial Sample App | Home</title>
</head>
<body>
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
  sample application.
</p>
</body>
</html>

$ bundle exec rspec spec/requests/static_pages_spec.rb   # pass

EmbeddedRuby for Dynamic title
<% provide(:title, 'Help') %>
<!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
  </head>
  <body>
    <h1>Help</h1>
    <p>
      Get help on the Ruby on Rails Tutorial at the
      <a href="http://railstutorial.org/help">Rails Tutorial help page</a>.
      To get help on this sample app, see the
      <a href="http://railstutorial.org/book">Rails Tutorial book</a>.
    </p>
  </body>
</html>

Rails should call the provide function and associate the string ’Home’ with the label :title.
The practical differences between provide and content_for are well explained here: http://api.rubyonrails.org/classes/ActionController/Streaming.html#label-Communication+between+layout+and+template


Using Layouts (to abstract) (eliminate duplication)

Restore the layout page that we discarded
$ git mv foobar app/views/layouts/application.html.erb

<%= yield %>
This code is responsible for inserting the contents of each page into the layout. using this layout ensures that, for example, visiting the page /static_pages/home converts the contents of home.html.erb to HTML and then inserts it in place of <%= yield %>.

When streaming, rendering happens top-down instead of inside-out.
YIELD: wait for it to provide it later. (to be filled)

Conclusion:

Seen from the outside, this chapter hardly accomplished anything: we started with static pages, and ended with… mostly static pages. But appearances are deceiving: by developing in terms of Rails controllers, actions, and views, we are now in a position to add arbitrary amounts of dynamic content to our site. Seeing exactly how this plays out is the task for the rest of this tutorial.





Chapter 4 - Rails Flavored Ruby

Use helpers.

In the layout:    <title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title> This relies on the definition of a page title (using provide) in each view, <% provide(:title, 'Home') %>    But what if we don’t provide a title? It’s a good convention to have a base title we use on every page, with an optional page title if we want to be more specific.

$ vim ./app/helpers/application_helper.rb    # created when sample_app initialized.
module ApplicationHelper

  # Returns the full title on a per-page basis.
  def full_title(page_title)
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      "#{base_title} | #{page_title}"
    end
  end
end

$ vim ./app/views/layouts/application.html.erb
<title><%= full_title(yield(:title)) %></title>

Now remove redundant Home page title, first modify the test
$ vim ./spec/requests/static-pages_spec.rb
      expect(page).to have_title("Ruby on Rails Tutorial Sample App")
$ bundle exec rspec spec/requests/static_pages_spec.rb    # test fails
$ vim ./app/views/static_pages/home.html.erb      # delete the provide title line
$ bundle exec rspec spec/requests/static_pages_spec.rb    # test pass


check it out

Rails console

$ rails c      # OR     $ rails console     works on top of ruby interactive console   $ irb

Types of environment for rails:
-Development (default)
-Test
-Production

Strings
>> "foo" + "bar"    # String concatenation
=> "foobar"

>> first_name = "Michael"    # Variable assignment
=> "Michael"
>> "#{first_name} Hartl"     # String interpolation
=> "Michael Hartl"


>> puts "foo"     # put string
foo
=> nil
The puts method operates as a side-effect: the expression puts "foo" prints the string to the screen and then returns literally nothing: nil is a special Ruby value for “nothing at all”.
>> print "foo"    # print string (same as puts, but without the newline)
foo=> nil

Ruby won’t interpolate into single-quoted strings:

Objects & Messages

"".empty?  true       "foobar".length       puts "Both strings are empty" if x.empty? && y.empty?

>>
nil.to_s => ""

>> nil.nil? => true
 
>> if s.empty?
>>   "The string is empty"
>> else
>>   "The string is nonempty"
>> end
 
>> if nil
>>   true
>> else
>>   false        # nil is false
>> end
=> false
 
>> if 0
>>   true        # 0 (and everything other than nil and false itself) is true
>> else
>>   false
>> end
=> true
  

>> string = "foobar" >> puts "The string '#{string}' is nonempty." unless string.empty? The string 'foobar' is nonempty. => nil

>> def string_message(string)
>>   if string.empty?
>>     "It's an empty string!"
>>   else
>>     "The string is nonempty."
>>   end
>> end
modules give us a way to package together related methods, which can then be mixed in to Ruby classes using include
"abcdxkjdcxw".split("x")

array     a = [42, 8, 17]         x = a.length  
a.sort   .shuffle .reverse    
Note that none of the methods above changes a itself. To mutate the array, use the corresponding “bang” methods (so-called because the exclamation point is usually pronounced “bang” in this context):
a.sort!

>> a.push(6) # Pushing 6 onto an array => [42, 8, 17, 6] >> a << 7 # Pushing 7 onto an array => [42, 8, 17, 6, 7] >> a << "foo" << "bar" # Chaining array pushes => [42, 8, 17, 6, 7, "foo", "bar"]
a.join # Join on nothing. => "428177foobar" >> a.join(', ')

>> (0..9).to_a # Use parentheses to call to_a on the range. => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> a = %w[foo bar baz quux] # Use %w to make a string array. => ["foo", "bar", "baz", "quux"] >> a[0..2] => ["foo", "bar", "baz"]

use the index -1 at the end of the range to select every element from the starting point to the end of the array without explicitly having to use the array’s length
a[2..-1]

Blocks

 
>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5
 
>> (1..5).each do |i|
?>   puts 2 * i
>> end




>> a[2..(a.length-1)]               # Explicitly use the array's length.
=> [2, 3, 4, 5, 6, 7, 8, 9]

3.times { puts "Betelgeuse!" }   # 3.times takes a block with no variables.

(1..5).map { |i| i**2 }          # The ** notation is for 'power'.

 %w[a b c].map {|temp| temp.upcase}   # downcase
 => ["A", "B", "C"]

('a'..'z').to_a.shuffle[0..7].join    0..7 take range

Hashes

are essentially arrays that aren’t limited to integer indices.
> user = {}   
> user["firstname"] = "Ali"
 => "Ali"
> user
 => {"firstname"=>"Ali"}
It’s important to note that the curly braces for hashes have nothing to do with the curly braces for blocks.

So far we’ve used strings as hash keys, but in Rails it is much more common to use symbols instead. Symbols look kind of like strings, but prefixed with a colon instead of surrounded by quotes. For example, :name is a symbol. You can think of symbols as basically strings without all the extra baggage

user = { :name => "Michael Hartl", :email => "michael@example.com" }


Since it’s so common for hashes to use symbols as keys, Ruby 1.9 supports a new syntax just for this special case:
>> h1 = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> h2 = { name: "Michael Hartl", email: "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> h1 == h2
=> true


Nested hashes.

>> params = {}        # Define a hash called 'params' (short for 'parameters').
=> {}
>> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" }
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
>> params
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
>>  params[:user][:email]
=> "mhartl@example.com"



inspect method

returns a string with a literal representation of the object it’s called on:
 puts (1..5).to_a.inspect    # Put a literal array.
[1, 2, 3, 4, 5]

 > user
 => {"first_name"=>"Michael", "last_name"=>"Hartl"}
> user.inspect
 => "{\"first_name\"=>\"Michael\", \"last_name\"=>\"Hartl\"}"
 
puts "It worked!", "It worked!".inspect
It worked!
"It worked!"

using inspect to print an object is common enough that there’s a shortcut for it, the p function:
>> p :name             # Same as 'puts :name.inspect'
:name

Note:

  • Parentheses are optional on function calls, Curly braces are optional when the hash is the last argument in a function call.
  • You can not use hyphens in symbols. Hence, in a hash you would have to stick to  " "

CSS

<%= stylesheet_link_tag "application", media: "all",
                                    "data-turbolinks-track" => true %>
calls the stylesheet_link_tag function with two arguments: a string, indicating the path to the stylesheet, and a hash with two elements, indicating the media type and telling Rails to use the turbolinks feature (new in Rails 4). This will create the output:
<link data-turbolinks-track="true" href="/assets/application.css" media="all"
rel="stylesheet" />

Classes

Everything is a class: literal constructor vs named constructor
s
= String.new("foobar")
a = Array.new([1, 3, 2]) => [1, 3, 2]
>> h = Hash.new => {} >> h[:foo] # Try to access the value for the nonexistent key :foo. => nil >> h = Hash.new(0) # Arrange for nonexistent keys to return 0 instead of nil. => {} >> h[:foo] => 0

s.class.superclass.superclass.superclass

String -> Object -> BasicObject -> nil


class Word def palindrome?(string) string == string.reverse end end

self = this in java. self is the object itself,


>> class Word < String # Word inherits from String. >> # Returns true if the string is its own reverse. >> def palindrome? >> self == self.reverse # self is the string itself. >> end >> end => nil

Ruby classes can be opened and modified, allowing us to add methods to them:
Rails adds a blank? method to Ruby.
>> "".blank?
=> true
>> "      ".empty?
=> false
>> "      ".blank?
=> true
>> nil.blank?
=> true
Note also that nil is blank; since nil isn’t a string, this is a hint that Rails actually adds blank? to String’s base class, which (as we saw at the beginning of this section) is Object itself.

instance variables is that they are automatically available in the views,

Instance variables always begin with an @ sign, and are nil when undefined.

Class

$ vim example_user.rb
class User
  attr_accessor :name, :email    # creates “getter” and “setter” methods 

  def initialize(attributes = {})   # called when we execute User.new. default value equal to the empty hash
    @name  = attributes[:name]
    @email = attributes[:email]
  end

  def format          # Just a to String
    "#{@name} <#{@email}>"
  end
end
$ irb
>> require './example_user.rb'
>> u = user.new
>> u.name = 'Ali'
>> u.format


===================================================================================================
===================================================================================================
===================================================================================================

Filling In the Layout

We’ll make use of Bootstrap, an open-source web design framework from Twitter.

$ vim app/views/layouts/application.html.erb
The added lines are in blue:
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--> <!--HTML if statement to add javascript for old IEs that don't support HTML5-->

</head>
<body>
<header class="navbar navbar-fixed-top navbar-inverse"> <!--Class names have special meaning at Bootstrap framework-->
<div class="navbar-inner">
<div class="container">
<%= link_to "sample app", '#', id: "logo" %> <!--Optional hash argument, here specifying id of the anchor. Later used for styling-->
<nav>
<ul class="nav pull-right"> <!--nav and pull-right classes on the ul tag have special meaning to Bootstrap-->
<li><%= link_to "Home", '#' %></li> <!--These link_to URLs will be given at later commits.-->
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</div>
</div>
</header>
<div class="container">

<%= yield %> <!--the yield method inserts the contents of each page into the site layout-->
</div>
</body>
</html>
Rails 4 uses HTML5 by default (indicated by <!DOCTYPE html>); we include some JavaScript code (known as an “HTML5 shim”) to work around the issue, this only works for IE: The first comment
it’s actually a conditional comment supported by Internet Explorer browsers for just this sort of situation. (if IE is less than v9 ...)

$ vim  app/views/static_pages/home.html.erb
<div class="center hero-unit">
<h1>Welcome to the Sample App</h1>

<h2>
This is the home page for the
<a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</h2>

<%= link_to "Sign up now!", '#', class: "btn btn-large btn-primary" %> <!--Bootstrap framework names-->
</div>

<%= link_to image_tag("rails.png", alt: "Rails"), 'http://rubyonrails.org/' %> <!--image_tag takes as arguments the path to an image and an optional options hash, here alt attribute of the image tag. Download and place rails.png logo to app/assets/images/-->
Download and place rails.png logo to app/assets/images/

Check it out: http://localhost:3000/static_pages/home

Bootstrap Front-end Framework

Bootstrap, a framework from Twitter that makes it easy to add nice web design and user interface elements to an HTML5 application. The Bootstrap framework natively uses the LESS CSS language for making dynamic stylesheets.

Add Bootstrap by adding the bootstrap-sass gem to the Gemfile.
Instead of LESS, Rails asset pipeline supports the (very similar) Sass language by default. bootstrap-sass converts LESS to Sass and makes all the necessary Bootstrap files available to the current application.

$ vim ./Gemfile
source 'https://rubygems.org'
ruby '2.0.0'
#ruby-gemset=railstutorial_rails_4_0

gem 'rails', '4.0.0'
gem 'bootstrap-sass', '2.3.2.0'
.
.
.
$ gem install bundler                # bundler needed once
$ bundle install

 $ vim config/application.rb
Add     config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)     as the last line inside class Application < Rails::Application

$ vim app/assets/stylesheets/custom.css.scss    
@import "bootstrap";               
This one line includes the entire Bootstrap CSS framework
Any stylesheets in this directory will automatically be included as part of the application.css file included in the site layout.
Filename custom.css.scss includes the .css extension, which indicates a CSS file, and the .scss extension, which indicates a “Sassy CSS” file and arranges for the asset pipeline to process the file using Sass.

With and without importing Bootstrap
 























Copyright and license Ruby on Rails Tutorial: Learn Web Development with Rails. Copyright © 2013 by Michael Hartl. All source code in the Ruby on Rails Tutorial is available jointly under the MIT License and the Beerware License.




Comments