You create a new user in linux with the following command. -m means create the home directory for the user.

useradd investingnote -m

Then you switch to the user.

su investingnote

Funny things happens, you can’t use up and down arrow in the terminal. It shows unreadable characters. This is because the login shell for this user is not /bin/bash but possibly /bin/sh. To check on this. Run command:

env

Possible output
TERM=xterm-256color
XDG_SESSION_ID=11
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
XDG_RUNTIME_DIR=/run/user/1001
LANG=en_US.UTF-8
SHELL=/bin/sh

Look for the last line, it tells me that I am using /bin/sh.

Change Login Shell to /bin/bash

vim /etc/passwd

You will see a line similiar to below:

investingnote:x:1001:1002::/home/investingnote:

Update it with

investingnote:x:1001:1002::/home/investingnote:/bin/bash

Now switch user and it will use /bin/bash as the login shell.

I am setting up NFS client to connect to my NFS server. In order for it to be mounted automatically whenever the server reboots, you need to add the entry to /etc/fstab.

10.01.03.45:/var/nfs  /mnt/nfs/var/nfs  nfs  auto,noatime,nolock,bg,nfsvers=3,intr,tcp,actimeo=1800 0 0

After you have added new mount entry in /etc/fstab file, the new mount won’t be automatically mounted after you save the file. In order to reload /etc/fstab, you can either restart the server or use the following mount command to mount all filesystems mentioned in /etc/fstab.

mount -a

Mount All Filesystems

When you set up a linux server like Ubuntu, CentOS, Redhat, by default the SSH port is listening at port 22. For security reason, you might want to change to a different port number, so it is harder for hackers to guess who wanna exploit SSH vulnerabilities. In order to change the default SSH port, you need to do the following two steps.

Change SSH Port

sudo vim /etc/ssh/sshd_config

Please note that under the /etc/ssh/ folder, there is a sshd_config and ssh_config.

What’s the difference between ssh_config and sshd_config file?

ssh_config: It is the configuration file for the SSH client on the machine you are running. Meaning that whenever you connect to other machines via ssh, this ssh_config file’s setting will be applied. It includes things such as port number, protocol version and encryption/MAC algorithms.

sshd_config: It is the configuration file for the SSH daemon service (sshd) that your machine is running. Meaning that whenever a client connects to your server via SSH, the client’s ssh configuration options needs to match the requirements set in sshd_config.


Since we want to change the server machine’s SSH listening port, so we need to change the sshd_config file. Open it with your favorite editor and you will notice the following line. Change the port to your desired port. Notice that don’t change the port to those default port already occupied by other programs.

# What ports, IPs and protocols we listen for

Port 22

Restart SSH Service under Linux

After modifying the sshd_config, you need to restart the SSH service in order to take in the updated config.

Under CentOS / RHEL / Fedora / Redhat

/etc/init.d/sshd restart

Or

service sshd restart

Under Ubuntu

service ssh restart

Then you are done. Trying to connect to your server with default setting now and it should throw error that “Connection refused”.

While upgrading Rails from V4.0 to V4.1.1, i encountered the error “Cannot define multiple ‘included’ blocks for a Concern” while deploying the code changes to production server:

 * 2014-09-13 10:00:35 executing `deploy:build_missing_paperclip_styles'
  * executing multiple commands in parallel
........
*** [err :: investingnote.com] rake aborted!
*** [err :: investingnote.com] ActiveSupport::Concern::MultipleIncludedBlocks: Cannot define multiple 'included' blocks for a Concern
*** [err :: investingnote.com] /home/investingnote/shared/bundle/ruby/2.0.0/gems/activesupport-4.1.5/lib/active_support/concern.rb:126:in `included'

I have a concern called notifiable.rb under app/models, the structure of the concern is very standard as in the Rails API for Concern. The following is the brief code for the concern and the model class (in a different file) that include the concern.

module Notifiable
   extend ActiveSupport::Concern
   included do
     require 'eventmachine'

     after_create :create_notification
     ...
   end
end

class Post
  include Notificable
end

I can’t see any problem with this code. I have found some people complaining this problem ActiveSupport::Concern and Rails.config.cache_classes. It is not really quite related to the problem i am facing. So i suspected it should be something wrong with the paperclip compatibility with Rails 4.1.1. Here is the git issue Error on rake paperclip:refresh:missing_styles

The solution is to update your Paperclip to V4.2.0 by running bundle update. Paperclip latest version is compatible with Rails 4.1.

bundle update paperclip

What is ORM? How Sails.js attributes validation works? How to validate Array size and Uniqueness in Sails.js? If you have any one of those questions. Read on.

What’s ORM?

ORM (Object-Relational-Mapper) is datastore agnostic using adapters to communicate with your favorite data-store. In another word, instead of using raw SQL statements (which maybe different based on which underlying database you choose), ORM provides an abstraction layer on top of the database and you can easily query, create or update records with the same source code. And it will be mapped to the underlying database statements by the different adapters.


Ruby on Rails use Active Record and Sails.js use WaterLine as the ORM for their framework. There are some similarity between Active Record and Waterline. Like model Query Methods, Validations and Associations. I have to say that in order to achieve the convenience that’s given from Active Record, WaterLine still have some way to go, but it is already doing a great job. That’s why I am using it for my production application.


How Sails.js Attributes Validation Works?

While doing my backend API service, I have the experience of finding a way to validate Array. By sharing my experience, you will understand how Sails.js attributes validation works. I am using MongoDB. The attribute data type supported contains Array. And I have a need to validate the Array size and the uniqueness among the elements. Initially the maxLength validator strikes me, because array also support the length method, so this maxLength validator should support both String and Array. However, I was wrong. I did some digging and here is why it is not working. You should do so as it is good for  you to understand how the framework works.

Look at WaterLine package.json file:

"dependencies": {
    "lodash": "~2.4.1",
    "async": "~0.9.0",
    "anchor": "~0.10.0",
    "q": "~1.0.1",
    "waterline-schema": "0.1.11",
    "node-switchback": "~0.1.0",
    "waterline-criteria": "~0.10.7",
    "prompt": "~0.2.12",
    "deep-diff": "~0.1.6"
  },

Waterline depends on ‘Anchor’, which is a javascript library that lets you define strict types and validates attribute values. And the validation from ‘Anchor’ is actually done by package ‘Validator’. Again, you can check this from the package.json under ‘Anchor’ package.


Go ahead and check rules.js file in ‘Anchor’. You can find all the validations rules documented in Waterline documents here. The “maxLength” validator method is defined as below:


var validator = require('validator');
...
'maxLength'	: function (x, max) { return validator.isLength(x, 0, max); }

How to Validate Array Size and Uniqueness in Sails.js?

Based on the code, we can tell that maxLength in the end calls validator.isLength method. So we need to go and check “Validator” package’s validator.js file.

validator.extend = function (name, fn) {
    validator[name] = function () {
       var args = Array.prototype.slice.call(arguments);
       args[0] = validator.toString(args[0]);
       return fn.apply(validator, args);
    };
};
//Right before exporting the validator object, pass each of the builtins

//through extend() so that their first argument is coerced to a string
validator.init = function () {
   for (var name in validator) {
      if (typeof validator[name] !== 'function' || name === 'toString' ||
         name === 'toDate' || name === 'extend' || name === 'init') {
            continue;
      }
      validator.extend(name, validator[name]);
   }
};
....
validator.isLength = function (str, min, max) {
    var surrogatePairs = str.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g) || [];
    var len = str.length - surrogatePairs.length;
    return len >= min && (typeof max === 'undefined' || len <= max);
};
..
validator.init();

Looking at above source code. When the "validator" is required, it will call the init() method, which actually convert the first arguments into type of 'String', which is called again on the extend() method.


By drilling down the source code, you should have a better understanding why maxLength doesn't work for Array. So what's the solution? You have to use custom validators.


Below is the sample code used in my Instameet server backend. With this code, you should be able to get started with the custom validations. In fact, the code is very simple and Sails.js is quite flexible.


 module.exports = {
  maxAttendees: 3,

  /**
   * Custom types and validations
   */
  types: {

    // Limit the max attendees to the property maxAttendees
    limitedAttendees: function(attendees) {
      return attendees.length <= Meet.maxAttendees;
    },

    // Make sure that the attendees are within the list of applicants
    withinApplicants: function(attendees) {
      var lastAttendee = attendees.slice(-1)[0];
      return this.applicants && this.applicants.length > 0 && this.applicants.indexOf(lastAttendee) >= 0
    },

    // Make sure that the newly added Array element doesn't exists in the existing Array
    uniqElement: function(array) {
      var lastElement = array.slice(-1)[0];
      return array.indexOf(lastElement) < 0;
    }
   },
.....
    confirmedAttendees: {
      type: 'ARRAY',
      limitedAttendees: true,
      withinApplicants: true,
      uniqElement: true
    }
}