In this assignment, we put all of the skills together. This assignment is intended to check whether you have learned the basic concepts of Rails development. For each part, there are examples in the blog application or in subsequent lessons, so you should be able to copy/paste into your new code, with changes to make everything work.
We are going to continue to use the git repository from the last lesson, but we will also use a new git branch for this. For your current branch, make sure you have committed all your changes and pushed them to github. Make sure that the rspec branch is active, so that you have all the changes from that branch. Then do the following commands:
git checkout -b full-assignment
git push -u origin full-assignment
Use the following commands to get started:
bin/rails generate model Order product_name:string product_count:integer customer:references
bin/rails db:migrate
bin/rails generate controller orders
Before you run rspec, you have to migrate the test database:
bin/rails db:migrate db:test:prepare
In your Order model, to validate that the customer_id in the order actually points to an existing customer record, you will need the line:
validates_associated :customer
To create the dropdown list for choosing the customer for the order, you can use this line:
<%= f.collection_select :customer_id, Customer.all, :id, :full_name, include_blank: true %>
In the rspec test for the order model, you can set up the subject with this line:
subject { Order.new( product_name: "gears", product_count: 7, customer: FactoryBot.create(:customer))}
In the rspec test for the order controller, you will need a factory that generates an order. But as each order belongs to a customer, the factory has to create the customer object too. To do this, FactoryBot uses the association method:
FactoryBot.define do
factory :order do
product_name { Faker::Lorem.word }
product_count { Faker::Number.number(digits: 3).to_i }
association :customer
end
end
The key point here is the use of association. Now, we can do order = FactoryBot.create(:order) and it will create an order for us and store it in the database, creating the necessary customer object as well. Unfortunately, that doesn’t quite solve all our problems. For the post method, we need to get the attributes for an order object. If we do attributes = FactoryBot.attributes_for(:order) it will not store anything in the database. It will also not create any attributes corresponding to the customer. So we have to create the customer object explicitly, and add its id to the list of attributes, as follows:
customer = FactoryBot.create(:customer)
order_attributes = FactoryBot.attributes_for(:order, customer_id: customer.id)
The resulting attributes could be passed in the parameters when testing the post method to create an order entry.
Good rspec testing validates that the correct page is displayed. If a redirect is expected to occur, one should check that the redirect goes to the right page, for example:
expect(response).to redirect_to orders_path
If a redirect does not occur, you should check that the right page template is displayed:
expect(response).to render_template(:show)
Here are a couple example tests from the orders request test that may help to explain rspec request testing:
describe "put order_path with valid data" do
it "updates an entry and redirects to the show path for the customer" do
order = FactoryBot.create(:order)
put "/orders/#{order.id}", params: {order: {product_count: 50}}
order.reload
expect(order.product_count).to eq(50)
expect(response).to redirect_to("/orders/#{order.id}")
end
end
describe "put order_path with invalid data" do
it "does not update the customer record or redirect" do
order = FactoryBot.create(:order)
put "/orders/#{order.id}", params: {order: {customer_id: 5001}}
order.reload
expect(order.customer_id).not_to eq(5001)
expect(response).to render_template(:edit)
end
end