Add a HTML form in Sails

By | 10/10/2020

Moving over from Rails to Sails – this one had me for a few days as forms were a doddle in Rails!
I’d set up the form and it was showing in the view OK, however when I submitted I was receiving a ‘Forbidden’ error in the view. I sorted that after a little reading… sorting the routing to get the form to submit to the database was another hurdle.

I’m going to assume you have a sails app set up, it’s connecting to the data base and you know what your form needs to do. I’ll create a series to set up an application from scratch which will end up being the walk through for this guide however to start with this is a stand alone post while it’s fresh in my head.

Let’s say you have a shop and you want to show the shop’s name on an index page – you need a form to add and edit them also.
First let’s generate a new page to for the form to sit on, all our stores sit in the stores folder so we need to run the following in the terminal:

$ sails generate page locations/new

To ensure the css styles get pulled in for the page we need to add the following to the bottom of /assets/styles/importer.less

@import 'pages/locations/new.less';

In the config/routes file we’ll also need to add a new route to point to our form, add the following to the bottom of the WebPages section

'GET /locations/new': { action: locations/view-new' },

This created a route https://www.example.com/locations/new to our new form and forwards the action to the locations-new controller in the api/controllers/locations directory.

If we open the views/pages/locations/new.ejs file we’ll see a new page has been created – this is a template and is the one rendered to the screen when we requested it in the url above.

Let’s add the form here and get that rendering.

We’ll be using a pretty simple bootstrap form for this as all the inputs are free type, however later down the line we’ll be moving some to selectors but let’s keep it simple to start with. 

Let’s create a div to hold the form and add some styling to centre on the page along with the Vue v-cloak flag

<div id="new" class="row" v-cloak>
  <div class="col-md-6 mt-lg-5 pt-lg-5 mx-auto">

Below that let’s create a new form and set up the action

<h1>Add New Store</h1>
<form method="POST" action="/locations" enctype="multipart/form-data">

This is a header and form wrapper.  The form has a method of POST as we’ll be wanting to send the server data from the form and we set the encryption type.

The next bit of HTML is super important and one that had me stumped for a while.  When I was submitting my form I was receiving a ‘Forbidden’ response and couldn’t work out why.  I had the routes set up correctly, controller was showing the form but nothing was getting passed through to the controller when I hit the Save button!

In RubyOnRails cross site forgery is embedded in forms automatically and you tend not to worry about it, in Sails it’s a little different as we needed to add it to our form.
To achieve this add the following

<input type="hidden" name="_csrf" value="<%= _csrf %>" />

The first part of your form should now look like this

<div id="new" class="row" v-cloak>
  <div class="col-md-8 mt-lg-5 pt-lg-5 mx-auto">
    <h1>Add New Store</h1>
    <form method="POST" action="/locations" enctype="multipart/form-data">
    <input type="hidden" name="_csrf" value="<%= _csrf %>"/>
      <div class="form-group">

We need to set up the POST action and route however let’s add the first of our input fields.

<div class="form-group">
  <label for="store_name">Store Name</label>
  <input name="store_name" type="text" class="form-control" id="store_name" placeholder="Store Name">
</div>

We’re adding a simple form group with a label for the store_name. 

Also we have a text field for the store_name, both this and the name in the label should be the same as the field in the  model, it doesn’t have to be but will mean you need to keep track of everything in the controller and things can get a little messy.

We just need to add the other inputs for the rest of the fields in the model.  You can view the finalised form in the repository.

Hitting save now gives us a 404 as the POST route is trying to send us to /locations, which doesn’t exist but also we need to add the POST action, run the following in the terminal:

$ sails generate action locations/create 

This generates a controller action api/controllers/locations/create.js as well as telling us to also add an API endpoint which we need to add to the config/routes.js file under the API section

This generates a controller action api/controllers/locations/create.js as well as telling us to also add an API endpoint which we need to add to the config/routes.js file under the API section

'POST /api/v1/locations': { action: 'locations/create' },

This handles the data submission however we still need to handle the redirect in the URL by adding the following route

'POST /locations/': { action: 'locations/create' },

Finally we need to re-build the SDK

$  sails run rebuild-cloud-sdk

and re-lift the server. I use port 5000 and silly mode to show all logs in terminal

$ sails lift --port=5000 --silly