Explore the intricacies of using Ruby on Rails to develop agile software solutions, with a focus on the has_many, through relationship and setting quantity. Our tutorial will guide you through creating the line_item model, setting up the has_many, through relationship, and implementing the quantity field, along with agile development approach insights.
Key Insights
- With the has_and_belongs_to_many relationship type in Ruby on Rails, there isn't a direct way to access the contents of the join table.
- An agile development approach in Ruby on Rails means building only what’s needed in the moment, revising it later on if necessary.
- To resolve a lack of direct access to the join table, a line_item model can be created to connect the products to the carts using the has_many, through relationship.
- Implementing the has_many, through relationship involves updating the cart and product models, and referencing line_item instead of the product in the create method of the cart_controller.rb file.
- The quantity field can be accurately displayed on the cart screen by stepping through line_items instead of products, since the quantity field is a property of the line_item model.
- When implementing the quantity field, the create method in the cart_controller.rb file needs to be modified to deal with quantities instead of just adding a single instance of a product.
This tutorial guides you through the process of creating a has_many, through relationship using Ruby on Rails, with an emphasis on setting quantity and the agile development approach.
This exercise is excerpted from Noble Desktop’s past web development training materials. Noble Desktop now teaches JavaScript and the MERN Stack in our Full Stack Development Certificate. To learn current skills in web development, check out our coding bootcamps in NYC and live online.
Topics Covered in This Ruby on Rails Tutorial:
The Has_many, Through Relationship, Setting Quantity
Exercise Overview
With has_and_belongs_to_many, every time you relate two model objects together, an entry is made in the join table, which relates those two objects. However, when you use the has_and_belongs_to_many relationship type, there isn’t really any way to access the contents of the join table directly (such as to add additional fields to it). We’ve hit a wall with our initial approach.
No need to feel bad if you reach this point in your own development work. Part of working in Ruby on Rails is being Agile in your development approach. In short, that means that when we encounter a obstacle, we pause, retool our approach, and forge ahead.
Agile Development
Agile software development is a huge topic, and a course in its own right.
In essence, Agile development just means that when implementing a new feature, we try our best to build only what’s needed in the moment. If, later on, it turns out that our approach wasn’t adequate, we can always go back and revise it to make it better. It’s easy to plan software to death drawing up database diagrams and API specs and zillions of mockups and never actually write a line of code. Agile proposes that it’s not only possible to take what’s written on the back of a napkin and just start building it in code—it can even be preferable. Why? Because the process of actually building a site often turns up all kinds of problems and challenges that you didn’t anticipate—and a fair number of the scenarios you did worry about might turn out not to be important at all.
Rails facilitates Agile development by providing a whole host of tools. Foremost among them is the Ruby language with its simple syntax, but other examples include the generators which build out huge blocks of standard code quickly, database migrations that let you keep track of and even reverse database changes, and support for integrated testing to ensure that changes to one part of the site don’t break existing features elsewhere.
So here, what we’re going to do is create another model and call it line_item. As shown in the diagram below, the line_item model will be used to connect the products to the carts. This type of relationship is called has_many, through. We’re going to say product has_many :carts through line_items. That way, we have a full-fledged model in between the ends of the many-to-many relationship. The quantity field can be a property of that line_item model.
No longer a mere join table, our Line Item will become an important player on the Rails stage.

- 
If you completed the previous exercises, you can skip the following sidebar. We recommend you finish the previous exercises (8A–9A) before starting this one. If you haven’t finished them, do the following sidebar. If You Did Not Do the Previous Exercises (8A–9A)- Close any files you may have open.
- Open the Finder and navigate to Class Files > yourname-Rails Class
- Open Terminal.
- Type cdand a single space (do NOT press Return yet).
- Drag the yourname-Rails Class folder from the Finder to the Terminal window and press ENTER.
- Run rm -rf nuttyto delete your copy of the nutty site.
- Run Git clone https://bitbucket.org/Noble Desktop/nutty.Gitto copy the That Nutty Guy Git repository.
- Type cd nuttyto enter the new directory.
- Type Git checkout 9Ato bring the site up to the end of the previous exercise.
- Run bundleto install any necessary gems.
- Run yarn install—check-filesto install JavaScript dependencies.
 
Setting up the Has_many, Through Relationship
- 
For this exercise, we’ll continue working with the nutty folder located in Desktop > Class Files > yourname-Rails Class > nutty If you haven’t already done so, we suggest opening the nutty folder in your code editor if it allows you to (like Sublime Text does). 
- 
You should still have a window with two tabs open in Terminal from the last exercise, the first of which is running the server. If you don’t, complete the following sidebar. Restarting the Rails Server- In Terminal, cdinto the nutty folder:
 - Type cdand a space.
- Drag the nutty folder from Desktop > Class Files > yourname-Rails Class onto the Terminal window (so it will type out the path for you).
- In Terminal, hit Return to change directory.
 - 
In Terminal, type the following: rails s
- Open a new tab (Cmd–T) leaving our server running in the old tab.
- In the new tab, cdinto the nutty folder:
 - Type cdand a space.
- Drag the nutty folder from Desktop > Class Files > yourname-Rails Class onto the Terminal window (so it will type out the path for you).
- In Terminal, hit Return to change directory.
 
- In Terminal, 
- 
In the Terminal tab where the server isn’t running, type the following to roll back (undo) the most recent migration that we ran: rails db:rollback
- Next we need to delete the migration file we just rolled back. On the Desktop, navigate to Class Files > yourname-Rails Level 2 Class > nutty > db > migrate 
- Find the file that ends with create_carts_products.rb 
- 
In Terminal, type the following command to delete the migration file: rails destroy migration create_carts_products
- 
Create the line_itemmodel by typing:rails g model line_item quantity:integer cart:references product:references rails db:migrate
- We need to go back to our models and update the relationships. Let’s start with the cart. In your code editor, open nutty > app > models > cart.rb 
- 
Delete the following line of code (around line 4): has_and_belongs_to_many :products
- 
Add the following bold code: class Cart < ActiveRecord::Base belongs_to :customer has_many :line_items has_many :products, through: :line_items endNow we have a choice when working with the cart. We can call cart.line_itemsand then access the product property of each line item as we step through them. Or we can callcart.productsand basically traverse directly over the entireline_itemstable and get to the other side of the many-to-many relationship.
- Save the file, then close it. 
- Let’s do the same thing with the product model. In your code editor, open: nutty > app > models > product.rb 
- 
Delete the following line of code (around line 5): has_and_belongs_to_many :carts
- 
Add the following bold code: class Product < ActiveRecord::Base validates :title, :sku, :price, presence: true validates :price, numericality: true has_many :line_items has_many :carts, through: :line_items has_one_attached :image
- Save the file, then close it. 
- Go to or reload localhost:,000 in the browser. 
- Click the Cart link at the top right. The cart is now empty because when we rolled back the migration, the items were deleted from the cart. 
- Go back to the homepage and click on a product. 
- For that product, click Add To Cart. The product should now appear in the cart. Notice that we didn’t have to update any of the code in the Cart controller. Nifty! 
Implementing the Quantity Field
Let’s work on getting the quantity field to work.
- 
In your code editor, open nutty > app > controllers > cart_controller.rb We need to modify the createmethod here to deal with quantities instead of just adding a single instance of a product.
- 
Around line 10, highlight the following code that adds the product directly to cart.productsafter the product is loaded:@cart.products << product
- 
Delete it, replacing it with the following bold code that refers to line_item:def create product = Product.find(params[:product_id]) @cart.line_items.build(product: product, quantity: params[:quantity]) @cart.save
- Save the file. 
- 
In your code editor, open nutty > app > views > cart > index.html.erb If we want to display the quantity accurately on the cart screen, we’re going to have to step through line_itemsinstead ofproducts. The reason we need to do that is that, again, we need to access theline_itemdirectly.
- 
Around line 20, edit the code as shown in bold: <tbody> <% @cart.line_items.each do |line_item| %> <tr>
- 
In that same block of code starting around line 21, add line_item.beforeproductas shown below (don’t forget the period).Sublime Text Users Only: If you select the word productthen hit CTRL–Cmd–G you can select all instances ofproducton the page. Then you just have to hit the Left Arrow key once to move the cursors to just before each instance of the word product and typeline_item.to quickly make the changes below.<% @cart.line_items.each do |line_item| %> <tr> <td id="thumbnail-div" class="hidden-xs"> <%= link_to line_item. product do %> <%= image_tag url_for(line_item.product.image.variant(resize_to_limit: [200,200])), ALT: product.title, class: 'cart-thumbnail' %> <% end %> </td> <td> <%= link_to line_item. product do %> <p><%= line_item. product.title %></p> <% end %> <p class="gray-text">Item #<%= line_item. product.sku %></p> </td> <td><input type="number" name="quantity" min="1" max="100" value="1"> <a href="#"><span class="glyphicon-refresh"></span>update</a> <a href="#"><span class="glyphicon-remove"></span>remove</a> </td> <td class="hidden-xs"><%= number_to_currency line_item. product.price %></td> <td class="total-price"><%= number_to_currency line_item. product.price %></td> </tr> <% end %>
- 
Select the bold code around line 33: <td><input type="number" name="quantity" min="1" max="100" value="1">
- Hit Return to delete it and create a new line. 
- 
Add the following bold code around line 34 to implement the quantity field: <td> <%= number_field_tag :quantity, line_item.quantity, min: 1, max: 100 %> <a href="#"><span class="glyphicon-refresh"></span>update</a>
- Save the file. 
- In the browser, reload: localhost:,000 
- Click on a product. 
- 
On the product page, try setting the quantity to 8 then click Add To Cart. You should be taken to the Cart and see that it added the product with a quantity of 8. However, you may notice that the first item we added has no quantity because we added it before we set the quantity code. We need to get that remove link working, which we’ll do in the next exercise. 
 
    
     
    