CRUD – create data

Now we're going to take what we've just learned, and use it to add the ability to create users in our application. If we look back to the routes we set up in app.js, we can see that we have two routes for creating a user, the form itself and the form action.

app.get('/user/new', user.create);     // Create new user form
app.post('/user/new', user.doCreate);  // Create new user action

Adding a new user form

To display the form in an HTML page, we need to do two things:

  • Create the Jade template
  • Link the template to the route

Adding the Jade template

By default Express will install with two Jade template files, layout.jade and index.jade. The layout template contains the HTML skeleton, including the DTD, <head>, and <body> tags. The index template extends the layout template inside the <body> tag.

For our MongoosePM application, we will keep this simple approach, and create a new extension template for each new page template we need. This is a great approach for rapid prototyping and development of a proof of concept. But before releasing an app, you'll probably want to spend more time on the templates and layout.

Let's get started and create the template file for our user sign-up form. In the views folder either copy index.jade or create a blank text file and call it user-form.jade. In that file, enter the following lines and save it:

extends layout

block content
  h1= title
  form(id="frmUserProfile", method="post", action="")
    label(for="FullName") Full name
    input(type="text", name="FullName", id="FullName")
    label(for="Email") Email
    input(type="email", name="Email", id="Email")
    input(type="submit", value="#{buttonText}")

Here you can see that we are extending the template layout, and defining a block of code for the content section of the layout template.

Note

For the rest of the templates in this book, we will omit the extends layout and block content lines for brevity, unless they are required to set context.

This page is going to be pretty minimal, having a <h1> tag containing the page title that we'll pass through as the variable title, and a blank form. The form only asks for the full name and e-mail address; the submit button expects a variable buttonText to be passed to the template and will use it for the value. We have set the form method to POST and left action blank. This means that the form will post to the same URL that is displaying the form. If we look back at our routes this is the behavior we are looking for:

app.get('/user/new', user.create);     // Create new user form
app.post('/user/new', user.doCreate);  // Create new user action

This is a technique we'll be using a few more times in this application.

Linking the view to the URL

Now that we have our display template ready, we need to link it to the routing. Our routing maps a GET request of the URL /user/new to the route user.create. So in our /routes/user.js file we need to create an export function called create. As part of this, we need to send the variables that the Jade template is expecting: title and buttonText. Your function should look something like the following:

// GET user creation form
exports.create = function(req, res){
  res.render('user-form', { 
    title: 'Create user', 
    buttonText: "Join!"
  });
};

That's pretty straightforward right? We can easily see this in action by running our application.

Tip

Restarting the application

If your application is still running, then refreshing the page in the browser will not reflect changes made to Node.js code, although you will generally see changes made to Jade and CSS files. To restart the application, go to the terminal window running the process and hit Ctrl + C to kill the process. Then run the following command ensuring that you are in the root folder of the application:

$ node app

Alternatively there are a few tools available to monitor and restart your Node server automatically, such as Nodemon and Supervisor, which are available at the following links:

https://github.com/remy/nodemon

and

https://github.com/isaacs/node-supervisor

Head back over to your browser and point it to http://localhost:3000/user/new—you should see something like the following screenshot:

Linking the view to the URL

Now, we're not going to win any design awards with this, but still, our form is up there with very little effort. Unfortunately, it doesn't do anything yet, so let's fix that right now!

Adding the create user function

The route we've declared to use—to handle the new user form—is user.doCreate, so we will create the doCreate export function in routes/user.js.

The bare bones of what we want to do are:

  1. Take the name and e-mail address from the new user form.
  2. Add the current date and time for modifiedOn and lastLogin.
  3. Create the new user.
  4. Save the new user to the database.
  5. Confirm the save operation to the console.

We will flesh this out soon, but that's the minimum functionality we're after. We'll use the Model.create() method we looked at before, to create and save the document in one go, so add the following lines to your routes/user.js file:

// POST new user creation form
exports.doCreate = function(req, res){
  User.create({
    name: req.body.FullName,
    email: req.body.Email,
    modifiedOn : Date.now(),
    lastLogin : Date.now()
  }, function( err, user ){
    if(!err){
      console.log("User created and saved: " + user);
    }
  });
};

Remember that if the operation is successful, then the saved object is returned to the callback function. So if you were to run this successfully you could expect to see something like the following returned to the console:

User created and saved: { __v: 0,
  name: 'Simon Holmes',
  email: '[email protected]',
  createdOn: Sun Apr 21 2013 15:53:07 GMT+0100 (BST),
  lastLogin: Sun Apr 21 2013 15:53:07 GMT+0100 (BST),
  _id: 5173fd53aef1909b49000001,
  modifiedOn: Sun Apr 21 2013 15:53:07 GMT+0100 (BST) }

Note how the createdOn value has been set using the default specified in the schema, and the unique key _id has been added, created, and returned to us.

Error trapping

This is all very well and good, but what if the save operation isn't successful? Well, we'll get an error object returned that we can look out for. We will first check if that error exists, and log it to the console for now. We will then check for the error code 11000. You may recall from Chapter 3, Schemas and Models that this is the error which MongoDB will return if the e-mail address already exists in the database.

Our callback function now looks like the following:

function( err, user ){
  if(err){
    console.log(err);
    if(err.code===11000){
      res.redirect( '/user/new?exists=true' );
    }else{
      res.redirect('/?error=true'),
    }
  }else{
    // Success
    console.log("User created and saved: " + user);
  }
}

So if an error is thrown while creating and saving the user we'll output it to the console, and redirect the visitor to /?error=true, except if the error code is 11000 when we redirect the user to /user/new?exists=true. We could use both of these techniques to let the visitor know what has happened.

Note

There are several other MongoDB error codes that you can check for, allowing you to be as specific and granular as you want. You can find them in the following link:

http://www.mongodb.org/about/contributors/error-codes/

Creating a user session

Now that we've error trapped, we need to do something more useful with the new user information than just log it to the console. In order to keep using the site we will need to store some of the user information in a session cookie, so that the application can tell who each visitor is. We will also set a Boolean session variable named loggedIn.

By updating the success section of our callback, we now have the following:

// Success
console.log("User created and saved: " + user);
req.session.user = { "name" : user.name, "email": user.email, "_id": user._id };
req.session.loggedIn = true;
res.redirect( '/user' );

We have used the session capabilities of Express to store some useful information about the current user that we will use soon. You'll see that the final thing we do is to redirect the visitor to the user profile page /user.

Note

You will notice that at the time of restarting the application, all existing sessions are lost as the default Express memory store does not persist outside of the running process. This can present a problem in live environments, but can be solved quite easily by using an external memory store to hold the session data.

Displaying the confirmation page

To keep things simple, we are going to use the user profile page as the confirmation page.

For now we will have a super-simple Jade template. For this create a template /views/user-page.jade and add the following under the block content section:

h1 Mongoose Project Management
h2= name
p Email: #{email}
  h3 Actions
  ul
    li
      a(href="/project/new") Create a new project
    li
      a(href="/user/edit") Edit user info
    li
      a(href="/user/delete") Delete #{name}
    li
      a(href="/logout") Logout #{name}

We have also added a section for page specific navigation, allowing the user to take specific actions. We will tie these up to code as we go along.

Next add the new export function to routes/user.js:

// GET logged in user page
exports.index = function (req, res) {
  if(req.session.loggedIn === true){
    res.render('user-page', {
      title: req.session.user.name,
      name: req.session.user.name,
      email: req.session.user.email,
      userID: req.session.user._id
    })
  }else{
    res.redirect('/login'),
  }
}

Note that we are checking to see if a user is logged in before rendering the user page template, sending it some user data from the session object. If there is no active session then the visitor will be redirected to the login page. We will create the login page when we have looked at how to use Mongoose to read data.

Try it out!

You can now save the files, restart the application, and head to http://localhost:3000/user/new. Try creating a few new users, and try registering a few with the same e-mail address to see the error trapping in progress. See how it works without having to do anything so mundane as creating a database? Refreshing isn't it!

Adding create project functionality

Managing projects in our application is similar to how we manage the users, so we won't go through it in great detail here. I will just point out the highlights and any differences. You can get the full code from the download that accompanies this book.

Routes

The following are the two main routes, to be added to app.js:

// PROJECT ROUTES
app.get('/project/new', project.create);      // Create new //project form
app.post('/project/new', project.doCreate);   // Create new //project action

New files and functions

You will need to create some new files and functions to build the functionality, and to display it in the browser. As a starting point you'll be looking at the following files:

  • Routing: You will need to create a new controller file /routes/project.js and two new functions exports.create() and exports.doCreate()
  • Display: You will need to create a new template file views/project-form.jade

At this point we will not be displaying the new project information on a webpage, just outputting to a console.log. Before we can view it on a page we need to learn how to query the database to find the correct information, as project data is not stored in a session in the same way as the user information.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.157.186