Practical 7
0. Finish Practical Sheet 6.
1. Taking Orders.
In this practical, we add to our online store the functionality
that allows us to record the buyer’s details and thus turn a
shopping cart into an order. As a first step in that direction,
generate the scaffold for an Order
model with the following components:
Order |
|
---|---|
name |
string |
address |
text |
email |
string |
pay_type |
integer |
In order to relate the integer
payment types to human readable
names, add the following enum
declaration to the generated file that
contains the order model:
2.
Generate a migration to add a column order
of type references
to the line_items
table.
Write the name of the generated migration file into the comment box below, as evidence that you have attended this practical.
In this generated file, replace the add_reference
command by the two lines
3.
Connect the orders
table with the line_items
table by
adding suitable has_many
and belongs_to
declarations (to which files?)
Add a parameter optional: true
to each belongs_to
call, to allow
this field to be empty.
As in the cart
model,
add the parameter dependent: :destroy
to the has_many
call:
when an order is destroyed, all its line items must go as well.
Then run the migrations:
rake db:migrate
4.
Add a 'Checkout'
button next to the 'Empty Cart'
button (which file?):
Then put both buttons inside a <div>
element with class
attribute
"actions"
.
5. There’s no point checking out an empty cart. In order to
decide this, the orders
controller needs access to the current cart.
For this, add
to the top of this controller (which file?).
6.
Then, after the private
declaration of this controller,
one can prevent empty orders from being placed by adding this code:
7. This expected behavior should be formulated as a test. In the
file orders_controller_test.rb
add:
Also modify the "should get new"
test so that it reads:
8. In the new setup, a line item now belongs to a cart, or to an order. In other words, at a given point in time, a line item might not have a cart (or an order) it belongs to. This optionality needs to be registered with the line items model. Change the lines that define the model relationships to
8a. If all works fine, commit the changes to your local git
repository, and push them to the github
cloud.
git add .
git commit -m "added checkout button"
git push
9. Forms.
Replace the contents of the order
’s new
view with:
10.
In the form itself,
that is in the partial file _form.html.erb
,
restrict the name
and email
input fields to
length 40 (size: 40
), and the address to 3 rows and 40
columns (rows: 3, cols: 40
). Turn the pay_type
field into a selection
and add an id
attribute like so:
and pass the argument "Place Order"
to the submit button.
Also, add the id
attributes :order_name
, :order_address
and :order_email
to the other three fields, e.g.,
11. Add these formatting rules to the end of the stylesheet
app/assets/stylesheets/application.scss
.
Now try it out: put some items into your cart and proceed to the checkout! How does it look?
12. As this form is intended for the outside world, the application
cannot rely on all input always being valid.
Add validation (to which model?) to ensure that the fields name
, address
, email
are all present and filled at submit time.
Also make sure, the pay_type
is one of the choices in the dropdown menu:
13. Modifying the validation rules almost always requires us to
adjust the fixtures so that they pass validation. In the fixtures file
orders.yml
modify fixture one
to be:
Then, in line_items.yml
, modify fixture two
to be:
13a. Test the application. If all works fine, commit the changes to
your local git
repository.
14. Create Order.
Next comes the create
action in the orders
controller. It needs to
-
Get the values from the order form to populate a new
Order
model object. -
Add the line items from the cart to that order.
-
Validate and save the order object.
-
In case of failure, display informative error messages that help the user to fix the problems.
-
In case of success, delete the cart, redisplay the catalog page and a message confirming receipt of the order.
This is done as follows.
In the Order
model, define a method that moves items from a cart to this order:
(Note that the append method <<
automatically sets
item.order_id
. Also note how item.cart_id
is set to nil
to prevent the item from disappearing when the cart will be destroyed.)
In the create
method of the orders controller,
add the line
after the assignment @order = ...
,
and replace the format.html
line under if @order.save
by
The new redirect requires us to modify the corresponding assertion
in the "should create order"
test: replace its last line by
14a. Now try it out and run the tests. If all works fine, commit
the changes to your local git
repository, and push them to the
github
cloud.
15. Atom feed. Feeds are news broadcasting services. You can subscribe to a feed and automatically receive regular updates. Here the good news to be spread is that someone ordered some product. In order to enable this service for our online store, we need to set up a new action. Recall that an action consists of three things: a controller method, a view template, and a route. First add the following method to the products controller:
To make a product aware of all the orders it is contained in, add a line
to the product model (which file?)
16.
The command format.atom
expects to find a view template
who_bought.atom.builder
in the views/products
finder
(where builder
is a template preprocessor, much like erb
, but better suited for
producing XML, and per default associated to .atom
files).
Create such a file with the following content.
and briefly try and make sense of this code.
17. Finally, add a matching route by changing
resources :products
in the file config/routes.rb
to:
18. Subscribe to http://localhost:3000/products/3/who_bought.atom
in your favorite reader, order the product from the store page, and get the good news.
18a. If all works fine, commit the changes to your local git
repository, and push them to the github
cloud.