Adding Records To a Database Via Form Submission In Rails

Over the last couple of weeks I have been learning how to make an admin area from scratch in a Rails application. This application displays online workshops. My latest task has been to grant users (stored in a users database table) access only to certain workshops (by adding their user_id and the relevant workshop_id into a relational database table called accesses). This is done by an admin user selecting a workshop displayed in a select menu and hitting a button 'Grant access'.

The intertwined workings of how the whole thing works would take me forever to write and each part has been a different challenge, but with the much appreciated patience and guidance from my boss it is coming together. In this blog post I thought I would focus as much as I can (without going off on a tangent of Rails interdependencies) on how I went about adding records into a relational database table by submitting a form. Hopefully the approach I took could be considered useful and adapted by people reading this blog entry.

The outcome of the overall task is that if a certain user has been granted access to a workshop then their user_id and the workshop_id(s) of the workshops they have access to will be stored in the accesses table.

I then make heavy use two methods written in the User class: has_access_to? and workshops. has_access_to? looks in the accesses database table for the relevant user (making use of a has_many? helper method) and checks to see if a certain workshop_id appears in the accesses table. If so it returns true. This is then called upon in a method written in the application_controller which is passed into a before_action. This will then be used to prevent unauthorised users accessing workshops for which they have not yet been granted permission. I won't go into much more depth about that part for now...

The workshops method returns an array of workshop objects from the Access table. Thanks to an attr_accessor :title defined in the Workshops class .title can be called on that workshops array which allows the relevant workshop titles to be displayed for users depending on their access permissions.

Back to adding records to a database using a form...

So firstly how did I make a form for each individual user? How could an admin user then go and use this to add the necessary individual data to the accesses table?

Well it all begins with creating the admin area which an admin user logs into by visiting:

http://localhost:3000/admin/session/new

To get everything in the admin namespace I just made admin directories within the controller and views directories and wrote the code for the admin stuff in there.

Please scroll down to see one of my previous blog posts for more info about setting routes in rails.

This is how my admin section is routed so far:

Image

The admin user logs in via a sign in form to get into the main admin area. I have made a basic dashboard in the admin area which displays some information about each user. There is an edit column with a link to a page for editing individual information for each user. Here is an example with the first 2 users (not real users... just made up details):

Image

Bootstrap has been used for the styling http://getbootstrap.com/. Maybe I will attempt to make it prettier at some point but for now my focus is on the functionality. The data in the table is being pulled in from the User database.

In the edit link, to allow us to navigate to the individual edit pages, the :id from the users database is passed in as the :id in the route. This happens in a table data cell in the dashboard table (in admin/users/index.html.haml).

The route (outputted by running 'rake routes'):

Image

In the dashboard table:

Image

The edit page currently looks like this and yes styling is very basic... but to give an idea:

Image

Again, the data is being pulled in from the users db table.

The view is created in admin/users/edit.html.haml

I am using HAML for the template markup instead of ERB. HAML looks simpler and I do like it, but everything has to be aligned and indented perfectly or it won't work so I struggled with that at first. I would recommend checking it out: http://haml.info/

Basically the html tags are displayed using % signs. You don't have to close tags. You don't have to write end. If you start the line with = it will output the return value of the ruby code to the screen. If you just want to run the code with no output you start the line with a hyphen - .

Below you can see the part of the view which creates the form. This is used to set up sending data in order to add records to the database. It displays all of the workshops that the user does not yet have access to in the select box (drop down menu):

Image

If you were wondering what the .row and .col-md-0.5 in pink are... that is Bootstrap styling code used to position stuff on the page.

To better understand the components that I would need in my HAML form, and how I could make use of Rails helper methods to send information I started by writing an example of the form in HTML:

Image

This can be broken down in to three sections:

1. form

The form starts with a form tag (you would fill in the action to specify where to send the form data once it has been submitted) and the method 'post' (which specifies how to send the form data so via a HTTP POST request).

2. input type = 'hidden'

This creates a hidden field. Hidden fields do not show up on the page meaning that a user cannot fill them in. The purpose of a hidden field is to send data that has not been submitted by a user. In this case we know that the admin user will need to select the workshop from the drop down (select) menu but the user_id will need to be grabbed from behind the scenes (by getting it from a params hash specified in the edit method of the users controller). Therefore by getting the user_id and putting it in a hidden field, we end up also sending the user_id to the Access database when the form is submitted.

3. select

Here we specify the workshops that will display as options in the select menu. There are more workshops than this but I am just showing one to make it clearer.

To convert this HTML idea into a form I could use with rails in my HAML template I started off by using a form_for tag.

The form_for tag is a Rails form helper method. Form helpers basically generate form markup. The form_tag generates a form tag like we had in the HTML code. It will also know to send the form as a POST request to the current page.

I had to specify [:admin, @access] rather than just @access (which is a variable set in the Users controller that instantiates the Access class - just so we know that we are communicating with the accesses table) because I am working in the admin namespace.

The if statement is checking to see if there are any workshops that the user doesn't have access to. If so then these workshops will display in the select box.

I then set the hidden field using a hidden_field helper tag. I passed in the name (as a symbol) and value arguments: f.hidden_field :user_id, value: @user.id

This will then update the user_id column in the Access table with the user id (which was '15' in the HTML example).

To create the select menu I used (you guessed it) a select helper tag. This generates a HTML select tag and a series of options. To generate the options I used another helper method options_from_collections_for_select. @selectable_workshops is the collection that this method will use to iterate over. For each iteration it will re-assign the values. These values are specified as arguments. I have set the first to “id” this will get the workshop_id which we want to put in to the accesses table. The second is a text method: “title” which will output the workshop titles in the select menu as options.

At this point the form is loaded with the power to know which data to send. But how does it actually update the info in the database table?

Remember that in the form_for method we told the form that we wanted it to send information to the accesses table through the @access variable which instantiates the Access class? This means that to send the data to the accesses table I needed to write a create method in the accesses_controller. Create is a POST action and has been set up as a route in routes.rb so that the application knows how and where to send the data.

In the accesses_controller the access_params method is set up to only permit the workshop_id and user_id to enter the accesses table. This is passed in as an argument to Access.create which is what needs to be called in order to update the Access database. The page is then refreshed thanks to redirect_to.

Image

Therefore if I granted the user with :id 15 access to the http-fundamentals workshop and ran Access.all in the rails console I could see that their data would appear in the accesses table:

Image

Image

I hope that gave some idea as to how I went about adding users to a database via submission of a form without going too deeply into the inner workings of the methods that were working together to make it happen. Hopefully the process of writing out a form in HTML first to get an idea of what it will need to contain and then looking at the available Rails helper tags and the parameters they take to recreate it will be useful. Also note the importance of the form_for tag and routing this to the create method in the controller for the database you want to update. Calling .create is what will cause the data to actually turn up in your database table.