Writing a Simple Blog on SailsJS: Good Practices for Beginners (Part 1)

Synopsis


This article is intended for beginners of their journey into NodeJS development, and introduces the beginner to developing on this platform using the SailsJS framework . In the article, we will consider the process of developing a simple blog, with accompanying explanatory materials, the purpose of which is to describe the initial skills of working with this framework - which is certainly an excellent basis for any projects on NodeJS. For a better understanding of the material, it is desirable to have a basic understanding of the Javascript programming language, and its server implementation of NodeJS , as well as at least a primary understanding of the MVC scheme, which is the basis of Sails. For a better understanding of the framework, you can read the documentation.on the official Sails website, as well as see castes describing how to work with Sails in sufficient detail. When writing an article, I tried to write the material as simple and clear as possible, this article will not tell anything new to experienced users, and some techniques may seem ineffective.

Preparation of the working environment


To get started, install the SailsJS framework itself, it is initially assumed that you already have the NodeJS package installed, and you have Internet access. In my case, my OS is Fedora 20, for your part it can be Mac OS X, Ubuntu and other OSs, in the example we will use the beta version, to install SailsJS globally enter the command
sudo npm install -g sails@beta

After that, we need to create a new project - in Sails this is done simply and clearly.
sails new sails-blog --linker
cd sails-blog/

I will explain - parameter
new
Titles that we want to create a new project, then we enter the name of the project, parameter
--linker
makes it so that in our project the files for the frontend are automatically connected: js, css, images, and so on, as well as the CoffeeScript and LESS files are automatically compiled, which is also very convenient - but more on that later. After that, we go to the directory with the generated project.

Connect Bootstrap - get acquainted with the organization of the frontend


In Sails, the side responsible for hosting the frontend is very conveniently organized, the server translates all the files that are located in the / assets folder located in the root of the project. The files from the assets folder themselves have approximately this access, I’ll explain on the fingers: suppose you want to place a certain image.png image, you place it in the assets / images / directory - in this case, when the server is running, this file will be available at the host / images /image.png . This is the basic information, and now install bootstrap, download the archive with the sources on LESS (I love this style language).

Unzip the less folder from the archive into assets / styles /- this should result in the location of the assets / styles / less folder, then rename the less folder to bootstrap (for convenience), then after unpacking the main part of bootstrap, we need to connect the glyphs, for this copy the fonts folder from the archive to the assets root (approx. / assets / fonts). Now open the file /assets/styles/importer.less in your favorite Sublime Text text editor : this file is connected to the main template by default and is constantly monitored by Grunt - it is automatically compiled into importer.css
accordingly then we will corrupt bootstrap by adding the line to this file
@import 'bootstrap/bootstrap';

To connect glyphs in the same importer.less you need to declare a variable that will indicate the path to the folder with glyphs, because our glyphs are located in the fonts folder - we add the following line to the file
@icon-font-path: '/fonts/';

To finally install bootstrap, we just have to drop the jquery.js and boostrap.js file into the assets / js / dependencies / folder .
With this, we will end the initial acquaintance with the organization of the frontend and statics in Sails and proceed directly to the development of the Blog itself.

Create Post API - the first acquaintance with models, controllers


To begin with, we will create an API complex - consisting of a model and a controller, which we will call post for obvious reasons; to create an API complex, enter the following command:

sails generate api post

The generated files will be located in the folders of the same name in the api / directory , Sails by default creates a CRUD API ready for operation, for more details see the video describing Sails .
Now we will open the Post model that we created earlier and start writing code, in the model we need to specify the attribute name, its type, and validator. Now I will give the contents of our model.

api / models / Post.js

module.exports = {
  attributes: {
      title: {
          type: 'string',
          maxLength: 120,
          required: true
      },
      description: {
          type: 'string',
          required: true
      },
      content: {
          type: 'string',
          required: true
      }
    }
};

The component of our model is built very similar to JSON, which makes it very understandable and convenient, as you can understand inside the atributes construct , we list the attributes of the model, in our case we need 3 attributes - a title, a short description and content. All 3 types have a string, the header has 2 validators: maxLength: maximum string length, required: whether this attribute is required when creating a new record (in our case, mandatory), then we set the parameters for the remaining 2 attributes, there are dozens of types for sails, and validators for all occasions (even the HEX color validator), see the full list here .

So, we have compiled our first model which will be responsible for our records in the database - and manipulations with them. Now we can move on to the main actions with the controller - api / controllers / PostController.js .

Manipulations with controllers also take place in a convenient JSON presentation, first we list what we want the blog to be able to do - and accordingly we will divide the tasks into controller elements. Our blog should be able to display a list of posts with a short description in descending order (new posts at the beginning, old at the end), be able to split the list of posts into pages (pagination) and the page on which we can see the full content of a single post with comments (disqus). Thus, for myself, I divided these capabilities into 3 controller attributes, and 3 main functions of record manipulation, index: displaying the last 10 posts. browse: display the full content of a particular zapsi.

pagination - splitting the list, and viewing the list on a specific slice of the list. Let's start writing code with the writing functionality - adding, updating, deleting. Inside module.exports - we will write the code.

Utilities

Creature

create: function (req, res) {
	var params = {
		description : req.param('description'),
		content     : req.param('content'),
		title       : req.param('title'),
	}
	Post.create(params).exec(function (err, post) {
		res.redirect('/post/watch/' + post.id);
		if (err) return res.send(500);
	});
}


In this code, as you understand, we describe the creation of a new record in the database, as I said in Sails, the CRUD API is built-in by default, which means that each url subcontroller can be passed parameters using GET or POST, and Sails can already process them.
Post.create - means 1) that we are going to work with the Post model and the create methodis responsible for creating a new record, in which we need to pass a list in which we indicate the attribute of the record, and the value of this attribute, in our case, the record should be generated from passing arguments to it in which we use CRUD, in the params list I specify the parameters to be transferred if you don’t understand how this is done, I’ll explain it on my fingers to create a record in our case - we send a POST request (for example, through Postman) with the parameters for title, description, content - to url / post / createparameters accepted on this url can be called using req.param ('parameter'), which we did. 2) In the exec method, we use an anonymous function that takes err as arguments that occurred during the creation of the error, and post as the data from the post we just created, which we further process in such a way that if the error occurs, it will produce page 500, when successful creation (when we receive the post data) we redirect to the page with a full description (we will consider this controller below) by passing the identifier of the post to the url.

The next auxiliary sub-controller we will make a data update sub-controller, which is very convenient if you need to do information editing.

Update

update: function (req, res) {
	var Id = req.param('id');
	var elem = {
		description : req.param('description'),
		content : req.param('content'),
		title : req.param('title')
	};
	Post.update(Id, elem).exec(function (err) {
		if (err) return res.send(500);
		res.redirect('/');
	});
}

In this case, the update method is very similar to the create method - the difference is that the first argument we specify the id of the record - which, like last time, we get from the passed parameter. The essence of this code, as I think, you have already caught. The last utility we will do is delete the record.

Delete

delete: function (req, res) {
	var Id = req.param('id');
	Post.destroy(Id).exec(function (err) {
		if (err) return res.send(500);
		res.redirect('/post');
	});
}

To delete a record, we only need to specify id.

The main part + work with views

Now we will consider writing the main “front” part of our application, which parts I described above, according to tradition, we will start from the index page, many can say that as an index I could just assign 1 page of a pagination slice, but I think it’s better for beginners to chew the excess time. and so is the index.

index: function (req, res) {
	Post.find()
		.sort('id DESC')
		.limit(5)
		.exec(function (err, posts) {
			if (err) return res.send(500);
			res.view({
				posts: posts
			});
		});
}


Now I’ll start explaining the code - the find method is responsible for finding records in the model, we do not call anything as arguments to it - then all records are suitable for matching, after that we sort the records in descending order - in this case I use id only as an example , if you are going to use such databases as MySQL, Mongo, etc. then you should replace id with createdAtfor obvious reasons, and the last on our list will be the product of the primary section of the list of posts with a limit of 5 entries. After all the procedures with the model are completed, she returns us a list of posts in the desired order and quantity: so that we can use it in our view further. As you remember from previous manipulations, we use an anonymous function in the exec method to perform the final data processing. So now let's move on to the key part - the display method, the view method is responsible for which we pass the list of what will be available to us when compiling the view, in our case it is an object list, for access I create an attribute list element called posts and the value is the posts attribute returned to us by the anonymous function.

Holistic View

watch: function (req, res) {
	var Id = req.param('id');
	Post.findOne(Id).exec(function (err, post) {
		if (!post) return res.send(404);
		if (err) return res.send(500);
		res.view({
			post: post
		});
	});
}

Here, as an argument to the findOne method , we pass an identifier argument - which is also a request, in response it gives us the data of a separate post, which we give access from the view method .

Next, we ’ll take a look at the pagination controller and blueprints path settings and go directly to the presentation.

page: function (req, res) {
	var page = req.param('page');
	Post.find()
		.sort('id DESC')
		.paginate({
			page : page,
			limit: 5
		})
		.exec(function (err, posts) {
			if (err) return res.send(500);
			res.view({
				posts: posts
			});
		});
}


Here we do almost the same as in the index controller, with the difference that we added the paginate method here , which takes JSON as an argument in which we must specify the limit of records per page, and the very page of the slice that we want to display. To make the slice page more dynamic - we create a page variable - with a request that will set the page - for convenience, we will pass this argument as a get request - without unnecessary query elements: directly, in the path configuration . To do this, open the config / routes.js file and start editing. Add the following to module.exports.routes :

  'get /post/:page': {
    controller: 'post', // Контроллер
    action: 'page' // Действие
  },

What is being done here? in principle, everything is extremely simple, we assign a path - the type of request first, url, and the transmitted attribute - : page - which we used in our controller ( req.param ('page') ) and simplified the option of sending it to the controller (I think it's better - / post / page? page = 2 ). At the same time with pagination we will set up a simplified control scheme for our utility functions:

  'post /post/create': {
    controller: 'post',
    action: 'create'
  },
  'get /post/delete/:id': {
    controller: 'post',
    action: 'delete'
  },
  'post /post/update': {
    controller: 'post',
    action: 'update'
  }


So, we made the basic manipulations with the Post controller and now for the final entry into force we only need to write a presentation - which will be the face of the application. If anyone is having trouble compiling the code, here is the full version of the Post controller with comments.

Representation

Sails submissions are built automatically according to the controllers, we created the Post controller - that means the folder with the views of this controller will be located at the address views / post / * , and the views have subcontroller names that have the views method , Sails supports many templating engines including Jade, Handlebars, HAML and others, but by default, EJS is built into it so our views will be built on it. Create a post folder in views , and add the index.ejs and page.ejs file with the following contents:

views / post / index.ejs and views / post / page.ejs

MY BLOG APP

<% _.each(posts, function (post) { %>

<%= post.title %>


<%= post.description %>
<% }) %>


_.each () as the first parameter is an array of values, the next callback which gives us data from a single element of the array (something like ng-repeat from angular), then we construct the data from which the values ​​should be repeated, I think those who those familiar with EJS understand that we enclose the values ​​of variables in <% =%> because this is text, or in <%%> we conclude functions (if it is very easy to explain). So I think you understand the main flow of information about EJS at least on an intuitive level - if not, then the documentation is there to help. And the last view is a single display of a particular post - views / post / watch.ejs

views / post / watch.ejs

<%= post.title %>


<%= post.content %>


On this, the main part of the functionality of our blog has been created - it can create, edit and delete posts, it includes pagination, and viewing individual entries, but for now we do not have a form in the admin panel that could create entries visually - but for starters, you can test using Postman having previously launched the test server with the command

sails lift


I hope the material from the first part was interesting and useful, the second part will describe the creation of sessions, authorization, and writing a simple admin panel, if you do not want to wait, or you misunderstood how the code should be written, you can see the full project code on github with full comments describing everything that is done there.

2 Part of the Article

Useful links and materials used in writing:

Also popular now: