CS312 - Spring 2012 - Class 10

  • administrative
       - take-home quiz is available on the course web page
          - follow the instructions
          - you may NOT use the Ruby to run your programs
       - everything we've covered through the semester
          - won't have much on rails
       - project discussion for next time
          - hand-in a 1-2 sentence blurb of a project that you've discussed with at least one person in the class
          - can hand-in one idea for up to 3-4 people
       - anyone interested in doing some web design on the side?

  • quick recap on rails last time
       - MVC framework
          - model handles the data
             - the interface with the database
             - validation
             - get, set, search, select-like queries, etc.
          - view handles the output/display to the user
             - consists of:
                - html files
                - css files
                - .erb (embedded ruby) files
          - controller
             - glues everything together
             - receive events and information from the outside world
             - handles all of the logic and queries
       - created a new rails project
          - rails new myproject
       - started the web server with rails server
          - this needs to stay running while you're debugging
          - by default the project is hosted on http://localhost:3000/
       - the public directory houses the static content
       - created a controller and the associated views
          rails generate controller Name forwards backwards
       
          - rails to generates a controller (and associated files) called "Name" with actions forward and backwards
             - this ends up in app/controllers/name_controller.rb
          - rails also generates views name#forward and name#backward
             - this ends up in app/view/name/
          - rails adds lines to the route.rb file:
             - get "name/forwards"
             - get "name/backwards"
             - now if we go to:
                http://localhost:3000/name/forward/
                http://localhost:3000/name/backwards/

                we see the views for the two actions
       - dynamic content generation
          - .erb files allow us to nest ruby inside html before the html is generated
             - <%= %> inserts whatever is the resulting value in the html
             - <% %> is used just for control statements, etc.
       - the controller is just a class that inherits from ApplicationController
          - each method in there generally maps to a route (i.e. a web page path)
          - this is where the key processing should happen
             - you should avoid work in the views
             - the views are for displaying and formatting data, not processing

  • linking between views
       - let's say we'd like to add links between forwards and backwards
       - we could put in a <a href=..., but it's very likely that this address wouldn't remain constant (we might move things, deploy somewhere else, etc.)
       - rails has a link_to function that allows us to link_to a page within the application
       - it also precomputes some paths for us to use in our program, in particular for ours:
          - name_forward_path contains the path to forward
          - name_backwards_path contains the path to backwards
          - in general, when you create a controller you will end up with: <controller_name>_<action_name>_path
       - using this, we could add the following to the bottom of forward to add a navigation bar:
          <p><%= link_to "Forward", name_forward_path %> <%= link_to "Backward", name_backwards_path %>

  • html templates
       - if we wanted this to be a nice navigation bar, we'd also need to add it to backward.html.erb
       - however, if we wanted to change this, we'd have to edit it in two places
       - if we look at the html pages that are being generated by our application, we see that there is a lot of html besides just what we're entering being generated
       - if we look in the app/views/layouts there is a file called application.html.erb
          - this file is the default html for any page in this application
          - inside it is a called to "yield" which generates the html page from the individual .erb calls   
          - if we can to have a global template change, we can make the change here
             - add the code above to the bottom, i.e.
             
             <p><%= link_to "Forward", name_forward_path %> <%= link_to "Backward", name_backwards_path %>
          - and now we have that information on all of the pages

  • symbols
       - rails makes extensive use of what are called "symbols"
          - we'll see them a lot, so get used to them
       - they're part of the Ruby programming language
       - a symbol is any string of characters that is preceded by a colon, e.g.
          :student
          :banana
          :class

       - symbols are just like any other values
          - think of them like a constant (but they don't have a value)
       - Ruby guarantees that if you use a symbol anywhere during a programs execution, it will have the same value and the value will be unique
       - it's a nice way to reference the same thing

  • grading applications
       - quick layout of the basic application on paper first
       - we'd like to develop a grade storing application
          - we will keep track of the grades for each student
          - a student may have multiple assignments
          - each assignment will have a score associated with it
       - we'd like to have multiple ways of getting at/editing the data
          - in one view, we can edit an individual student's scores and add assignments/scores
          - in another view, we can see all the students with all of their grades

  • student class roster application
       - create a new project
       - generate "scaffolding" for our students project
          - model
             - statements to generate our database
             - a class for interfacing with the database (inherits from ActiveRecord)
          - controllers to handle basic functionality
          - views to display default information

          $ rails generate scaffold Student name:string
          
             - created a db/migrate file (for setting up the database)
             - created a model class for us
             - setup a controller for us (students_contoller.rb)
             - setup a view for us (students)
                - the view has multiple files in it
             - setup routes for us in the route.rb file
             - setup some base .css files for us

       - first thing, let's setup our database
          - cd into the db (database) directory
          - if we look in here it's created an empty database for us:
             development.db

             - if you look in it it doesn't have any tables yet
          - if we go into the "migrate" directory there is a file with a timestamp and "_create_students.rb"
          - if we look inside this we see:
             class CreateStudents < ActiveRecord::Migration
              def change
              create_table :students do |t|
              t.string :name

              t.timestamps
              end
              end
             end


             - rails has generated some ruby code (in fact a class) that will create a database table for us

          - rake is a command-line tool that comes with rails that does things for us.
             - in this case, we're going to tell it to go ahead and migrate the database

             $ rake db:migrate

             (in /Users/dkauchak/classes/cs312/lectures/lecture9-rails/working/grades)
             == CreateStudents: migrating =================================================
             -- create_table(:students)
              -> 0.0009s
             == CreateStudents: migrated (0.0010s) ========================================

             - it tells us that it created the table
             - one of the advantages of this approach (vs. trying to make the table ourselves) is that we can undo/rollback migrations
          - rake
             - rake stands for "Ruby make"
             - "Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files."
             - very common tool for c/c++
             - can read more about rake files if you're interested
       - now if we look in the development.db we see our table there
          sqlite> .tables
          schema_migrations students

       - if we now got the our web application in the browser we'll see that the default controllers and views for students
          http://localhost:3000/students/
          
       - even without doing much of anything, we can add new students, etc.
       - controller
          - if we look in app/controllers we see there is a file called student_controllers.rb
          - just like other controllers, it is a class that inherits from ApplicationController
          - the methods inside this class are called depending on the url as a subdirectory of "students/"
             - index is called if no name is specified
             - show is called if the url looks like "students/1" or "students/15"
                - params[:id] is the number following students
             - new is normal (i.e. is called when "students/new" is visited
             - and many more...
                - http://guides.rubyonrails.org/routing.html
          - if we look at these functions we can learn a little bit about what's going on

  • basic chain of events when a page is visited
       - the routes.rb file is checked to figure out where to route the command (i.e. which controller)
       - a new instance of that controller is instantiated
       - the particular method for that controller is called
       - a view is then instantiated
          - the view gets data from the controller
       - the html file is generated from the view (and associated files)
       - the html is served up to the user

  • adding in the assignments
       - now we'd like to add the assignment
       - we don't need another controller or view, just another database
          rails generate model Assignment assignment_number:integer score:decimal student:references

          - the student:references tells Ruby that we want an entry the references our student database
          - if we look at the migration file we see:
          class CreateAssignments < ActiveRecord::Migration
           def change
           create_table :assignments do |t|
           t.integer :assignment_number
           t.decimal :score
           t.references :student

           t.timestamps
           end
           add_index :assignments, :student_id
           end
          end

       - as always, after generating a new model we need to actually create the database rake db:migrate
       - if we look at the tables in the database now:

          CREATE TABLE "assignments" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "assignment_number" integer, "score" decimal, "student_id" integer, "created_at" datetime, "updated_at" datetime);
          CREATE TABLE "students" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "created_at" datetime, "updated_at" datetime);

          - we have now have an assignments table with the cross-references student_id

  • now we need to state the relationship between assignments and students
       - the model enforces constraints
       - if we look in app/models/assignment.rb we see it has:
          belongs_to :student

          - if added this because of the student:references
       - we'd also like to tell rails that we can have more than one assignment per student
          - in app/models/student.rb we can add:
             has_many :assignments to student.rb
          
             - the main benefit of this is that it will allow us to retrieve all of the assignments associated with a given student using just . notation (it does the join syntax, etc. for us)

  • updating the route.rb file
       - we now need to tell the route.rb file that assignments is a nested resoure

          resources :students do
           resources :assignments
          end

          - this nests the assignment pages on top of the student page, e.g. notice that:

          http://localhost:3000/students/1/assignments/create

          routes to the AssignmentsController


  • Now let's generate the controller for the assignment
       rails generate controller Assignments

       - which generates controllers and viewers for us