2.3 Adding Items to Orders
To fully give meaning to orders, we'll need to be able to add items to them. Just as we're used to doing in regular Rails, we'll create some code to enforce the relationship between the order and item entities. We'll also create the routing and controller code to allow for new items to be added to an order.
1.Introduction3 lessons, 12:00
2.Building the API10 lessons, 1:53:48
3.Conclusion1 lesson, 01:08
2.3 Adding Items to Orders
Back in the previous lesson, we managed to create a mechanism for listing and also creating orders. Through these two methods we can accomplish such tasks. Now we're gonna add the possibility to add new items into our orders. After all, the customer is going to want to eat something in our restaurant. And the things that he eats will need to be registered in that order. So we're gonna provide the mechanism to accomplish that task. The first thing that we need to do is to generate a model. So we're gonna do that. I'm gonna a bash command in my VIM editor, so we'll use rails-api g model. And we'll call it item. The item for now will just have a name, because really there's no need to have any other piece of information right now. So we're gonna go to the console and type in this command. When we do it you will see some files being created, namely the migration file, the item model, and some test files. With this we can go straight to the command line and type in rake db:migrate so we don't forget. This way the items table will be created. You might be thinking how can I add the items in one way or another. Well, you can totally generate a scaffold instead of just the model. You will have the possibility of adding those items yourself, or we can use a tricky thing, which is to use the rails console command. I'm gonna use this just to add in some items so we can test it out. Remember that the main reason I'm not using the scaffold generator is because it would be more of the same. This is actually a different thing that I can teach you about. So, let's use item.create like this and pass in a name. The name that I'm going to choose, for example for the first one, is gonna be soup. Then we're going to create another one for example, a Steak and Potatoes, another one for example, let's see, Fish and Chips, and yet another one called for example, Pudding, for a dessert. Okay, you can see all of those SQL queries. It might become a little confusing at first, but you'll get the gist of it. Basically, we have four different items already. By using straight Ruby code, we don't need to resort to an API procedure to do it. So now we can move forward. The main step of this lesson is to focus on how we can interact those items with our orders. Now about that method really. What is it that's necessary for the controller to have? Well, I'm thinking of a method that will basically take the item's ID and build a new order item into the order. Let's type that in as we think through it. So we're gonna have a new order at least so we'll type in order equals, let's see order.find params and then the id. This will be part of the URL so we'll be able to retrieve the order based off the id. Next we're gonna have for example an order item which will be something in these terms. Let's see we're gonna build a new order_item based off the orders. There you go. And now we'll need to refer to that item's ID. So we'll use params[item_id]. Now in this specific scenario, you will see that we have a lot of assumptions. First of all, we're assuming that we have an order item class or an entity really. Remember in the first drawing in Lesson 1.2 where I talked about the order items? Well this is it. We're gonna have that intermediate model to connect both item and order. So, we'll pick up on the order items and build a new one that refers to both the order and the item. And that's it. Now, let's just finish up this add method by calling, if we can save the order item, then, we're going to render, for example, a JSON with the order item. There. Now, we're also going to pass in, for example, a 204 status code, or rather a 201, meaning that we've created something new. Otherwise, we're just going to pass in the order item's errors. Something in these terms. Something along the lines of line 19 when creating the order. But in this case, we want the order item's errors, just like so. Remember that instead of 201, we can type in created like this, and the same goes for the unprocessable identities status code which matches 422. We'll just leave it like this, as you can see. This is the main process of the add method. We basically create a new order item that refers to the item's ID. Now, let's take care of that order item as well. We'll invoke the model generator the same way as we did for the item, but this time for the order item. It is going to refer to the order, so we use order:references, as well as the item, so item:references. Now, let's pick up on the quantity as well. After all, if we want, for example, two puddings, one for each of the couple, then we should increment the quantity, instead of just creating a new record in the database. This is much more normalized. So, we'll pick up on that. Generate and migrate the changes right away. There you go. The order items is there. And actually we can go to, let's see, models order, and say that the order has many order items. That's the first part. And then the fact that it has many items through these order items. So we type that in like you see. This is the has many through relationship type that active record has. Now if I go to the order item, you will see that we already have those relationships in the model. In the item there's really nothing that we need do, so from here we'll be able to go back to the controller. Let's see, just to double check that everything is okay, we will find the order, create a new order item based off the ID parameter and then ensuring that the order item is saved or not. The last thing that we need to do is to test it out. Let's see, let's go to bin/curl, remember this file? We are going to create one more function called add_item. Let's go there. Let's create this function really quick and basically I'm just gonna copy whatever is on the create_order function because it's really really similar but it seems that I've made a mistake hold on. Let me just copy it again. There you go. Now in terms of the data that we're going to send, we're going to send for example, item.jason or rather add_item.json. Next instead of using tables/1/orders we are going to add that item. So this is going to be the URL. And then, instead of using this URL, we're going to provide an extension, called add. Also, we need to pass in an order ID, so we'll use the first one. Let's just make sure that the first order belongs to the first table. Let's see, let's run curl and then localhost 3000/orders. Let's see how this behaves. Oh, by the way, we need to boot up the Rail server first hand. So there you go. Now let's do that. Send the curl command and let's see the first ID. So ID of 1 belongs to the first table. So we're good on that. We can use tables/1/1 as the order ID and then use add. You might be wondering where is this URL typed in our application. Well it's not yet. So let's go ahead and do that first. Config/routes will need to have a new route. So we'll pass a block here, let's see let's just paste that in. There you go. And now for each specific order, we'll create a new post route. So the post route will be called, for example, add or better a symbol post add. And then on member. Remember that you can have routes that belong to the collection or are associated to the collection or to each specific order. The fact that we're using member, will affect one single order. Now that this is done we can go back to our script. So we're gonna send a post request with a content type, the file, which we're going to create right away and then the URL which seems to be all right. Now let's go to bin, then item or rather add item.json. Let's open that up and create a JSON file that closely represents what we need, what's going to be interpreted from the application. We're gonna have an item ID, which will be for example, one. Most likely the soup will be added into that order. So let's try and run bin/curl and then add_item because that's name of the function. We'll press enter now and you will see the entire response. It seems that it was created and then we will have the order item right there. So ID of 1 order_id, item_id, and we don't have the quantity. Well the quantity is something that we really need to fix. Let's go to migrate here, and then choose, let's see, which one is a migration? It is this one, create items, or rather the order items. So let's provide a default value here, which is going to be 1. We should have done this beforehand, but it's okay, we can just roll back the changes from the database and then migrate them again. So, we're going to type in rake db:rollback, there you go, the order items table was dropped. And now we can migrate the changes once again. So rake db:migrate, there you go. Now for every time we add a new item, it's going to default the quantity to one. So let's do this again. Let's add the item. And now you can see the quantity is just 1 now. So, good job. Now we have successfully added order items to relate the items and the order for our customers. Now let's perform a quick change, and that is to manipulate the quantity if the item's already there. Just increment the value of the quantity. Let's go to controllers, or this controller and just isolate this really quick. Okay, I just focus the add method really quick. And now we need to make sure that the item is already there. So we're gonna do something like this. order_item, this variable will try to have the order that's related to this item ID. So, we're gonna do something like OrderItem.where, and then item_id equals that specific item_id parameter. So, we'll do something like params[item_id]. Now, let's just retrieve the first record. If the order item is there, then we're going to try and increment it. So if the order item's there we'll pick it up and type in .increment with the bank and we'll pass in the attribute which is going to be the quantity. And that's it. Now, if the order item is not there, then we're going to assign it as you see here. So we're just going to build a new object with that item_id. Also, we need to extract this piece of code into the appropriate logic. As you can see, we have two different if and else cases and this is not good, so we need to re-factor this into a more proper solution. Here is a different solution that will not include two if statements but just one. It might look a little confusing, but I chose to do this, this way so you could understand a little bit behind the Rails and active record mechanics. So here's what I've done. I'm going to find for the order item which has this order_id, and item_id, we forgot about the order's reference. And then, we're going to choose the first item, because we just want that. And then we're going to imcrement it directly. But not using the bang method like so. Using increment with a bang will automatically save it. With this, we just want to increment the value. Then, if this doesn't exist, we are going to build a new order item. So if this doesn't exist, or better, this should actually be rescue, because if the first item retrieves nil, then increment would automatically throw an error. So we're gonna rescue any exception and build a new order item if the first instruction doesn't succeed. So we'll build a new object if the other one fails to be retrieved. At the end we'll just save and render whatever needs to be rendered. So that's it. So I'm just gonna save the file and run this bin/curl command again. Let's try and do that, let's press enter now and you will see that the quantity is updated for 2. Now let's change the bin/curl script a little bit. And instead of going to the first order we'll go to the second one. Let's do that. Let's add another item but to a different order and you will see the second order being identified. A new ID for the order item and the quantity as well. So there you go. Both scenarios are being covered successfully. We are now able to add different kinds of items to our orders.