ࡱ > 9 ; 6 7 8 - bjbj # " j 8 W s \ m# " " " " " " " $ % ' Z # @ # '# H" H" H" " H" " H" H" H" PFB2d l H" " =# 0 m# H" ( ! X ( H" ( H" H" # # H" m# ( : Sessions HyperText Transfer Protocol (HTTP) was not designed to aid web sites in tracking users activities. When a user makes a request for a browser page, the server responds to the request and then disconnects. The server can store the IP (Internet Protocol) address, but it may not be unique. Often several computers share the same IP address. Web sites need some way besides the IP address to keep track of their visitors. This is especially true of on-line stores. Users typically put something in their shopping cart and then continue shopping on the site. And stores want to encourage this behavior. They want customers to buy a number of products when they visit. There are two ways for web sites to track user activity. One is by depositing a cookie on the users hard drive, and the other is URL rewriting. There are several kinds of cookies, but the one that we will look at just puts some text into temporary storage and deletes it when finished. URL rewriting involves adding an identification number to the URL string. This is actually less safe than storing a cookie, since the string is sent unencrypted, and use of the back button on the browser can destroy it. The session is a part of a Rails application whether it is used or not. Data in it are stored as a hash. The session only has room for 4K, so you cant put very much in it. So the easiest thing to do is to just use the session to store the shopping cart id. The cart itself can be stored in a database table or a flat file. The following application is designed so that a student can select courses for his or her schedule. Registration Application We can add the equivalent of a shopping cart to our schedule application. There is one important change. In a shopping cart, buyers are allowed (maybe even encouraged) to select several copies of the same item. But when registering, students pick a course only once. We assume that we have the same schedule application as before. It allows students to list courses and find courses, but they cannot create or delete courses. That is left to the system administrator and scheduling staff. In an actual application, students have to sign into their university accounts in order to register. This application allows them to gather a selection of courses before doing so. They will have to sign in before they can save the courses to their schedule. This is the way many shopping sites work. They allow a customer to add items to a shopping cart before they check out and provide credit card numbers. This means that we have to create a connection between the courses chosen and the session id. The session is a stand-in for the student/user at this point. The most efficient way to handle this is by creating a new table for our database that connects the two. The fields will be the course id and the connection to the session. The connection to the session can be managed in several ways, but perhaps the easiest is to simply create a table that will maintain a connection to the session. We can call this table cart. It needs only to have a single field, the id that Rails always provides. We can use a scaffold command to create it. (Dont for get to create the actual table using rake db:migrate.) rails generate scaffold cart Once we have it, we can store the cart id in the session by adding the following to the application controller class ApplicationController < ActionController::Base protect_from_forgery private def current_cart Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound cart = Cart.create session[:cart_id] = cart.id cart # return the cart end end Next we need a table to store the courses chosen by the student. This contains cart id course id pairs. When a student clicks on a button to add the course to his/her schedule, the course id and the cart id are inserted into the table. Again it is easiest to create this table using the scaffold command. rails generate scaffold choice cart_id:integer course_id:integer There are now a number of models, controllers and views that have to be changed. Start with the models. Add the following lines to choice.rb in the model folder. class Choice < ActiveRecord::Base belongs_to :course belongs_to :cart def credits course.credits end end The first two lines create a connection between items in the choice table and ids in the course and carts tables. The credits method is only used to return the credits for the course that is being added. The class stored in course.rb already has validation commands in it. We can now add connection ones. class Course < ActiveRecord::Base default_scope :order => 'number' has_many :choices validates :number, :name, :credits, :presence => true validates :credits, :numericality => {:greater_than_or_equal_to => 1} validates :number, :uniqueness => true end The first line, default_scope :order => 'number', tells the model to always order the results of a query by the course number. The next line connects the course table to the choices one. This means that one course could be in many student carts. Finally the cart model requires a complete rewrite. class Cart < ActiveRecord::Base has_many :choices, :dependent => :destroy def add_course(course_id) current_choice = choices.where(:course_id => course_id).first if current_choice == nil current_choice = Choice.new(:course_id => course_id) choices << current_choice #appends a value end current_choice #returns a value end def total_credits choices.to_a.sum { |list| list.credits} end end Again this class connects the cart with the choices class, just as the course class did. It also removes all dependent records in choices if the main record is destroyed. This is useful when emptying the cart. The method, add_course, checks to see if the course is already in the cart. If not, it adds it to the cart by appending it to the choices already there. If it is in the cart already, it returns it, but it does not add it again. The total_credits method adds up all the credits in the cart and returns the value. There are two views to fix. The first is in list_courses in the schedule folder. We have to add a button so that students can add a course to their cart. Here is a portion of the code. <% @courses.each do |course| %>
<%= notice %>
<%= item.course.number %> | <%= item.course.name %> | <%= item.course.credits %> |
Total Credits | <%= @cart.total_credits %> |
<%= button_to "Empty Cart", @cart, :method => :delete, :confirm => 'Are you sure?' %>
<%= link_to 'Back', schedule_index_path %>
Finally the method that empties the cart is in the carts controller. When finished, the code left by the scaffold command sends the user back to a carts page. This is very confusing. To fix this, go into the carts controller and change the redirection in the delete method. # DELETE /carts/1 # DELETE /carts/1.xml def destroy @cart = Cart.find(params[:id]) @cart.destroy respond_to do |format| format.html { redirect_to(schedule_index_url) } format.xml { head :ok } end end Some web stores have decided not to deal with users that have set their browsers to refuse cookies. Web sites with heavy traffic can use GUIDs. A GUID is a Global Unique IDentifier. Generally, a GUID consists of a random number created using the time on the computer in nanoseconds and some feature of the server. In the past this was the network card MAC (Media Access Control) address. But after the Melissa worm used this to infect computers world-wide, Microsoft changed the GUID algorithm. The string, 3F2504E0 4f89 11D3 9A 0C 03 05 E8 2C 33 01, is an example of a GUID. The numbers are in hexadecimal. b ^ _ g h i R S Z 2 E O l ¾º᱒| h08 h08 h ^J h h ^J h 5 h ^J h ^J h h ^J h 5h h 6h h <