Adding a Star Rating system to your spplication - Step 2 - Putting the Foreign Key in the Flow

When building a system based on a reltional database developers are challenged to deal with all the foreign keys. In the Getting Started section we scaffolded the bookings table and auto-generated the create.blade.php view which allowed us to create new bookings. The challenge with this screen is, with two foreign keys, it led to confusion and potential error for the user. Confusion because the user would not know what to fill in for the memberid and courtid, and error because, if the user fills in a memberid or courtid which doesn't already exist in the other table, it will lead to an "integrity constraint key violation". This is perfectly sensible and useful - how can you book a court which doesn't exist or book use a member that doesn't exist?

The following are three simple ways of dealing with foreign keys fields on forms:

  1. Replace them with dropdown lists which look up correct data from another table
  2. Once you've added user login capability, you can allow the currently logged in user to, for example, book a court and pick up the appropriate member id from it's relationship with the logged in user
  3. The foreign key can be included in the flow of the activity the user is performing

In the getting started section we used the first approach. We replaced the freeform text input fields with two dropdowns which looked up the appropriate data in the respective tables and filled in the correct id field (in the background) for submission by the form.

In the security section, we described how to get the memberid by walking the one-to-one relationship between user and member thereby obtaining the memberid from the user's login.

In this post, I'll describe the final way to deal with the problem of foreign keys on our forms by putting the foreign key in the flow of the use-case. The scaffolder already relies heavily on this approach. The Read, Edit, and Delete actions of the BREAD capability are all included as links on each row of the list of items you are Browsing.

In this way, the user gets to select the specific row of the item they wish to perform the action on. The way this works in practice is that the foreign key field for the specific item is passed to the controller function through the route. The controller then uses it appropriately to find the relevant item and perform that action. In the case of the edit($id) function, the controller retrieves all the details of the item - in this case member - and passes them to the view.

In this section we will duplicate this approach. We will allow the user to select which court they want to rate in advance of arriving at that screen. The create($courtid) controller action will receive the $courtid as an argument. It will then pass this $courtid to the ratecourt.blade.php view as a view variable. The ratecourt view can then place the value on the form. In this way the user will not have to enter the data on the form or pick the value from a dropdown. One less piece of data to enter and have to look up leads to an overall improvement in usability and user experience.

To create a ratecourt($courtid) action in the court first add the following function the file app/http/controllers/courtratingController.php

public function ratecourt($courtid)
{
    return view('courtratings.ratecourt')->with('courtid',$courtid);
}

This function accepts the $courtid as an argument and then passes that same variable to the courtratings.create view as a view variable called courtid. In order for this ratecourt($courtid) function to work we need a corresponding route. Add the following route to app/routes/web.php

Route::get('/courtratings/ratecourt/{court}','courtratingController@ratecourt')->name('courtratings.ratecourt');

Finally, we a corresponding view to show the ratings. This view will be almost identical to the courtratings.create view with some small differences. To get this view - take a copy of the file app\resources\views\create.blade.php. Call your copied file ratecourt.blade.php. Once you've made the copy go ahead and edit ratecourt.blade.php. The create view is made up of the outer file which controls the overall look - it then pulls-in a list of fields. Given this we will have to duplicate and change the fields view also. To do this copy the file resources\views\courtratings\fields.blade.php to ratecourt_fields.blade.php in the same folder. Now modify the file ratecourt.blade.php so that it picks up on your new list of fields as follows:

Once this is done you can make the change to the ratecourt_fields.blade.php as follows

This means the courtid field in the form will be populated with the $courtid view variable which was passed to it from the controller. Now that we are passing the data through rather than having the user enter it we make the field readonly to ensure the user can't change the courtid. It's a good idea to move this field to the top of the list of fields to make it clear. Having done this visit http://localhost:8000/courtratings/ratecourt/4 - this will pass court number 4 through via the route to the controller and then on to the view. The form should look as follows

Now the user sees the court they will rate but can't modify the court. The rating is still entered as a text field rather than as a star rating but we'll get to that. In the next post we'll look at using our new approach of passing the courtid through the controller to the view to allow us to link from one of the list of courts on the Browse view.

Leave a Reply