Asaf Shakarchi

Software development, hmm... software development :-)

Ember Forms

Smart, Intuitive forms for Ember.js styled with Bootstrap, Multi layouts and Validation support.

As my favorite web framework is emberjs, I lately needed forms support for one of my projects with the following set of features in mind:

  • Styled for Bootstrap but easy to stil differently.
  • Different layouts such inline and horizontal
  • Validations where validation rules are defined in model/controller and form supports for:
    • Change color & icons when validation rule fails.
    • Show error message per form input.
    • Submit button with async support that changes its styles & get disabled during async call.

So here is the result: https://github.com/indexiatech/ember-forms

Demo & docs: http://indexiatech.github.io/ember-forms

Bootstrap for Ember Is Born

Bootstrap is an amazing set of pure CSS3 / HTML 5 components, while EmberJs amazes in its beauty of making web applications right.

You can just hook both projects together by using Bootstrap as is in Handlebars templates, But soon enough, you will find yourself asking questions sucha s:

  • How do I interact between Bootstrap events and Ember (such as Controllers)?
  • How to pass Bootstrap components data from Ember (such as Controllers)

I’ve seen few options about the integration between both, but:

  • They are not easy and fun to use, they make the ease of Bootstrap too complex.
  • They are not well documented.
  • Development is too slow, I haven’t seen anything new lately.

So! I’m excited about a project I’ve been working lately with some guys to integrate Bootstrap & EmberJs together in a way that doesnt make Bootstrap usage more complex than using it as-is but providing great integration with EmberJs components.

Links!

Nodejs-model Is Born

I’ve been struggling lately to find an appropriate way to handle models correctly, In one hand, these noSQL DBs such CouchDB have great flexibility and I didn’t want to ruin that with a blowing up ORM framework, in the other hand once the application grows a little bit more than a contact list app, then things become messy.

While writing a larger app with Node, I find myself struggling with finding solutions to problems such: (there are few more but these are the main)

  • Validating a document (model) properties (application level) before storing it in the DB.
  • A minimal schema where each attribute is defined per model to ensure no allowed attributes leaks into the model.
  • Automatically convert a property value when a value is set.
  • Filter critical, sensitive attributes when transfering the model on the wire to external clients.
  • Updating an existing domain via an accessibility-aware method (you may want users to update their profile but not letting them directly change their password attribute)

So I couldn’t really find a good module to achieve all of that without sticking a giant into my lightweight app, so I built one, it’s named nodejs-model, available here: https://github.com/asaf/nodejs-model

For now, read the docs on the github repo for more info, i will post series of posts about nodejs-model in the near future.

Nodejs Deployment: Building and Configuring on Amazon Linux AMI

Logging in and updating system to latest

SSH your shiny new VM,

Now lets update the system to the latest:

1
sudo yum update

Install OS dependencies

We’r going to build Node.js from sources, some dependencies (such as gcc) are required:

1
sudo yum install gcc-c++ make openssl-devel git

Cloning n Building Node.js

1
2
3
4
5
6
7
cd
git clone git://github.com/joyent/node.git
cd node
git checkout v0.10.13 #check for other stable tags by executing 'git tag'
./configure --prefix=/usr/local/node
make
sudo make install

Go grab a cup of coffee… :–) …

Configuration

1
2
3
sudo useradd _yourappuser_
passwd _yourappuser_
sudo su - _yourappuser_

Put your app

Now put your app in ~, for instance:

1
2
3
4
cd
pwd
#/home/_yourappuser_
git clone _https://myhost.com/myapp myapp_

Init.d

We would like to have nodejs to start automatically as a service, to do so, lets create an init.d file Note: you have to change the properties in the file such as yourappuser, myapp to your app folder and server.js to your node app file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
cat << 'EOF' > /etc/init.d/nodejs

#!/bin/sh

#
# chkconfig: 35 99 99
# description: Node.js /home/yourappuser/myapp/app.js
#

. /etc/rc.d/init.d/functions

USER="_yourappuser_"

NODE_ENV="production"
DAEMON="/usr/local/node/bin/node"
ROOT_DIR="/home/yourappuser/myapp"

SERVER="$ROOT_DIR/server.js"
LOG_FILE="$ROOT_DIR/app.js.log"

LOCK_FILE="/var/lock/subsys/node-server"

do_start()
{
        if [ ! -f "$LOCK_FILE" ] ; then
                echo -n $"Starting $SERVER: "
                runuser -l "$USER" -c "NODE_ENV=$NODE_ENV $DAEMON $SERVER >> $LOG_FILE &" && echo_success || echo_failure
                RETVAL=$?
                echo
                [ $RETVAL -eq 0 ] && touch $LOCK_FILE
        else
                echo "$SERVER is locked."
                RETVAL=1
        fi
}
do_stop()
{
        echo -n $"Stopping $SERVER: "
        pid=`ps -aefw | grep "$DAEMON $SERVER" | grep -v " grep " | awk '{print $2}'`
        kill -9 $pid > /dev/null 2>&1 && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE
}

case "$1" in
        start)
                do_start
                ;;
        stop)
                do_stop
                ;;
        restart)
                do_stop
                do_start
                ;;
        *)
                echo "Usage: $0 {start|stop|restart}"
                RETVAL=1
esac

exit $RETVAL

EOF

Add execution permission to the nodejs init script

1
sudo chmod +x /etc/init.d/nodejs

Pre Routing to port 80

Linux does not allow non super users to listen to ports < 1024, assuming your application listen to port 8080, You would probably like to pre route any traffic arriving from port 80 to your node app that listens to port 8080

You can do this by the pre routing nat capability of Iptables

1
2
3
4
5
chkconfig iptables on
service iptables start
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443 #if you want SSL too
service iptables save

Configuring node-http-proxy

It is common to install http proxies such as nginx on front of nodejs, This architecture has many advantages such as raising security level, listening natively to port 80, load balancing, multiple node apps support via url rewrite, etc…

I personally think that the best approach, which is very native to node apps is to use https://github.com/nodejitsu/node-http-proxy,

Which have several advantages:

  1. Reverse proxies incoming http.ServerRequest streams, WebSockets, HTTPS
  2. Minimal request overhead and latency
  3. Battled-hardened through production usage
  4. Very native for nodejs apps

TODO: Will post more details in the future but you can simply visit “https://github.com/nodejitsu/node-http-proxy” site.

https://github.com/pkrumins/nodejs-proxy

Installing CouchDB Instance on Amazon AMI Using Build-couchdb

This post explains how to install CouchDB on Amazon AMI using build-couchdb/

If you want to install couch from sources without build-couchdb tool, read: Installing CouchDB instance on Amazon AMI is a working link

build-couchdb does the following things:

  1. Install general dependencies via yum (such as gcc, ruby, automake, rubygems, etc.)
  2. Clone the ‘build-couchdb’ project, initalize and update its sub modules (will clone CouchDB itself, curl, gnulib, etc), These are all the dependencies that CouchDB needs in order to be compiled.
  3. Compiles all dependencies
  4. Compiles CouchDB linked with the compiled dependencies.

Okay, go grab coffee and lets start!

Launch Instance

Login into EC2, and launch a new instanc and choose Amazon Linux AMI, You can of course choose other Linux flavours (you are not going to use Windows right?),

But I really suggest going with Amazon AMI, it is EBS backed, ships with AWS tools installed and has a RHEL style package management using yum.

Once your instance is launched, SSH it, i’m sure you can do.

Now lets updated the system to latest:

1
sudo yum update

Installation

Installing OS dependencies

1
2
sudo yum install gcc gcc-c++ libtool curl-devel python27 help2man texinfo ruby-rdoc zlib-devel openssl-devel make automake rubygems perl git-core
sudo gem install rake --no-ri --no-rdoc

If you don’t want to get into troubles where build-couch tries to patch autoconf-2.69 because of old python version (< 2.6) then link to python 2.7, at least during the time couch is being built.

1
2
sudo mv /usr/bin/python /usr/bin/python_org
sudo ln -s /usr/bin/python2.7 /usr/bin/python

Clone build-couchdb

git clone git://github.com/iriscouch/build-couchdb cd build-couchdb git submodule init git submodule update

Optional: Upgrade SpiderMonkey

build-couch uses not an official Mozilla SpiderMonkey version, but considered to be very stable, if you would like to replace it with other versions then do the following, You can safely skip this, proceed only if you have a good reason to do so

1
2
3
4
5
6
7
8
sudo yum install mercurial
cd
hg clone --verbose http://hg.mozilla.org/releases/mozilla-release
cd mozilla-release
hg checkout FIREFOX_XX_0_RELEASE --clean #replace XX with the tag you wish
rm -rf ~/build-couchdb/dependencies/spidermonkey/js
rm -rf ~/build-couchdb/dependencies/spidermonkey/mfbt
cp -r js mfbt ~/build-couchdb/dependencies/spidermonkey

Building CouchDB and its dependencies

Now lets build Couch, you can replace 1.3.1 with any CouchDB release you wish to build, Or change the installation location.

1
2
sudo rake git="git://git.apache.org/couchdb.git tags/1.3.1" install=/usr/local/couchdb-1.3.1
sudo ln -s /usr/local/couchdb-1.3.1 /usr/local/couchdb

Now go eat something, drink (another?) coffee, take a shower (you will have time for all of them, I promise.)

You should expect the following output:

Plugins done

Now lets see what we’ve built:

1
2
3
4
5
6
7
8
9
cd /usr/local/couchdb-1.3.1
ls bin

> aclocal       autoheader2.13  autom4te2.69    autoreconf2.69  autoupdate2.59  ct_run       erl       genctd       ifnames2.62  pkgdata
> aclocal-1.11  autoheader2.59  automake        autoscan2.13    autoupdate2.62  curl         erlc      genrb        ifnames2.69  run_erl
> autoconf2.13  autoheader2.62  automake-1.11   autoscan2.59    autoupdate2.69  curl-config  escript   icu-config   js-config    run_test
> autoconf2.59  autoheader2.69  autoreconf2.13  autoscan2.62    couch-config    derb         genbrk    icuinfo      libtool      to_erl
> autoconf2.62  autom4te2.59    autoreconf2.59  autoscan2.69    couchdb         dialyzer     gencfu    ifnames2.13  libtoolize   typer
> autoconf2.69  autom4te2.62    autoreconf2.62  autoupdate2.13  couchjs         epmd         gencnval  ifnames2.59  makeconv     uconv

Lets execute Couch to ensure it can be executed.

1
2
3
4
5
sudo ./bin/couchdb

> Apache CouchDB 1.3.1 (LogLevel=info) is starting.
> Apache CouchDB has started. Time to relax.
> [info] [<0.32.0>] Apache CouchDB has started on http://127.0.0.1:5984/

You can open another terminal to ensure Couch replies properly:

1
2
3
curl http://127.0.0.1:5984

> {"couchdb":"Welcome","uuid":"9db29433ea76ccfaa81726f6ace742f4","version":"1.3.1","vendor":{"name":"The Apache Software Foundation","version":"1.3.1"}}

Configuration

Replace Python link

To avoid breaking yum and other things, it is adviced to return the python binary link back to its original version

1
2
sudo rm /usr/bin/python
sudo mv /usr/bin/python_org /usr/bin/python

Run Couch on isolated user and correct files ownership

1
2
3
4
5
# add couchdb user
sudo adduser --system --home /usr/local/couchdb/var/lib/couchdb -M --shell /bin/bash --comment "CouchDB" couchdb

# change file ownership
sudo chown -R couchdb:couchdb /usr/local/couchdb/etc/couchdb /usr/local/couchdb/var/lib/couchdb /usr/local/couchdb/var/log/couchdb /usr/local/couchdb/var/run/couchdb

couch ini file

Lets create couch ini file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat << 'EOF' > /usr/local/couchdb/etc/couchdb/local.ini
[couchdb]
#read more here: http://guide.couchdb.org/draft/performance.html
delayed_commits = false

[httpd]
port = 80
bind_address = 0.0.0.0
socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}]
WWW-Authenticate = Basic realm="administrator"
;WWW-Authenticate = bummer

[couch_httpd_auth]
require_valid_user = true

[log]
level = error

[admins]
EOF

Password protection

1
2
export PASS=`</dev/urandom tr -dc '12345!@#$%qwertQWERTasdfgASDFGzxcvbZXCVB' | head -c20; echo ""`
echo "admin = ${ADMIN_PASSWORD}" >> /usr/local/etc/couchdb/local.ini

Couch is smart enough to hash the passwords.

Logs Rotation

1
2
3
4
5
6
7
8
if [ ! -e "/etc/logrotate.d/couchdb" ]
then
  # add couch.log to logrotate
  sudo ln -s /usr/local/couchdb/etc/logrotate.d/couchdb /etc/logrotate.d/
  # change to daily rotation
  sudo sed -e s/weekly/daily/g -i /usr/local/couchdb/etc/logrotate.d/couchdb
  #logrotate -v -f /etc/logrotate.d/couchdb 
fi

Run CouchDB on startup

1
2
3
4
5
6
7
8
9
10
# run couchdb on startup
sudo ln -s /usr/local/couchdb/etc/rc.d/couchdb /etc/init.d/couchdb
sudo chkconfig --add couchdb
sudo chkconfig --level 345 couchdb on

sudo service couchdb status
#Apache CouchDB is not running.

sudo service couchdb start
#Apache CouchDB is running as process 5047, time to relax.

Now it’s really time to relax, enjoy :–)

Q Promises With CoffeeScript

If you are using NodeJS (or for some other reasons you need to do many async invocations), then you probably came across “https://github.com/kriskowal/q”.

Using Q with CoffeeScript is great as code blocks are much more organized and looks cleaner.

Here’s an example:

Defining promises with CoffeeScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
q = require 'q'

exports.hello = () ->
  d = q.defer()
  d.resolve 'hello'
  d.promise

exports.world = () ->
  d = q.defer()
  d.resolve 'world'
  d.promise

exports.die = () ->
  d = q.defer()
  d.reject 'bye world'
  d.promise

And here are Mocha sample of Q propagations and error handling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
assert = require 'assert',
promises = require './promises'

describe('Promises', () ->
  it 'Simple', (done) ->
    promises.die().then(
      (val) =>
        #handle val
      (err) =>
        assert.equal err, 'bye world'
        done()
    )

  it 'Test Promises Propagation', (done) ->
    promises.hello().then(
      (val) =>
        assert.equal val, 'hello'
        promises.world()
    ).then((val) =>
        assert.equal val, 'world'
        done()
    )

  it 'Test promises propagation with error', (done) ->
    promises.hello().then(
      (val) =>
        assert.equal val, 'hello'
        promises.die()
    ).then((val) =>
        promises.world()
    ).then(
      (val) =>
        #we wont get here
      (err) =>
        assert.equal err, 'bye world'
        promises.world()
    ).then((val) =>
      assert.equal val, 'world'
      done()
    )
)

Installing CouchDB Instance on Amazon AMI

One of our platform is based on CouchDB, we host everything on Amazon EC2 and while Amazon lacks with CouchDB support, I have decided to build our own CouchDB server.

So here’s a guide, how to install CouchDB on Amazon AMI (Amazon Linux):

Launch Instance

Login into EC2, and launch a new instanc and choose Amazon Linux AMI, You can of course choose other Linux flavours (you are not going to use Windows right?),

But I really suggest going with Amazon AMI, it is EBS backed, ships with AWS tools installed and has a RHEL style package management using yum.

Once your instance is launched, SSH it, i’m sure you can do.

Now lets updated the system to latest:

1
[ec2-user@ip ~]$ sudo yum update

UPDATE

Before proceeding with this guide, which compiles CouchDB from sources without any automated tool

I found this project: https://github.com/iriscouch/build-couchdb

Which maintains its own CouchDB dependencies and perform the build for you, if you choose this approach, check out this post: Installing CouchDB instance on Amazon AMI using build-couchdb is a working link

But if you still want to build from sources (which is more depdendent on Amazon’s dependencies) proceed reading.

Installing CouchDB via EPEL

Enabling EPEL repo, we need some packages missing in standard Amazon repos:

1
2
3
4
5
6
[ec2-user@ip ~]$ vi /etc/yum.repos.d/epel.repo

...

#change to enabled=1
enabled=1

Now if you don’t care to work with old CouchDB version, you can simply install it by:

1
2
[ec2-user@ip ~]$ yum info couchdb
[ec2-user@ip ~]$ yum install couchdb

But if this is not sufficient for you like us and you want a more updated version, proceed reading :–)

Installing latest CouchDB

Current CouchDB version is 1.3.1, but this guide should work for future versions as well (unless CouchDB folks decides to do major changes)

Install Dependencies

We are going to build CouchDB from sources, Couch is written in http://www.erlang.org/, so few dependencies are needed:

(Note: Don’t forget to enable EPEL repo, see above!)

1
2
3
4
5
6
7
8
9
[ec2-user@ip ~]$ sudo yum groupinstall "Development Tools"
[ec2-user@ip ~]$ sudo yum install perl-Test-Harness
[ec2-user@ip ~]$ sudo yum install erlang-erts
[ec2-user@ip ~]$ sudo yum install erlang-os_mon
[ec2-user@ip ~]$ sudo yum install erlang-eunit
[ec2-user@ip ~]$ sudo yum install libicu-devel
[ec2-user@ip ~]$ sudo yum install autoconf-archive #only available in EPEL repo
[ec2-user@ip ~]$ sudo yum install curl-devel
[ec2-user@ip ~]$ sudo yum install erlang-etap

From Couch folks:

While CouchDB builds against the default js-devel-1.7.0 included in some distributions, it’s recommended to use a more recent js-devel-1.8.5.

And since Amazon AMI only ships (via EPEL repo) with 1.7.0, we’r going to build js-devel-1.8.5: If you feel comfortable with js-devel 1.7.0, you can just:

1
[ec2-user@ip ~]$ sudo yum install js-devel

OR: if you have the energy, or this is going to be a production environment, then install js-devel from sources:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ec2-user@ip ~]$ cd ~
[ec2-user@ip ~]$ wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.13.tar.gz
[ec2-user@ip ~]$ cd autoconf-2.13
[ec2-user@ip ~]$ ./configure --prefix=/usr/local/autoconf-2.13
[ec2-user@ip ~]$ sudo make install

[ec2-user@ip ~]$ cd ~
[ec2-user@ip ~]$ wget http://ftp.mozilla.org/pub/mozilla.org/js/js185-1.0.0.tar.gz
[ec2-user@ip ~]$ tar zxvfl js185-1.0.0.tar.gz
[ec2-user@ip ~]$ cd js-1.8.5/js/src/
[ec2-user@ip ~]$ /usr/local/autoconf-2.13/bin/autoconf
[ec2-user@ip ~]$ ./configure
[ec2-user@ip ~]$ make
[ec2-user@ip ~]$ sudo make install #this installs js-devel under /usr/local

Some references:

Building CouchDB from sources

1
2
3
4
5
6
7
8
9
[ec2-user@ip ~]$ cd ~
[ec2-user@ip ~]$ git clone https://github.com/apache/couchdb.git
[ec2-user@ip ~]$ cd couchdb
[ec2-user@ip ~]$ git checkout -b 1.3.1 1.3.1
[ec2-user@ip ~]$ ./bootstrap #should output: You have bootstrapped Apache CouchDB, time to relax.
[ec2-user@ip ~]$ ./configure --with-erlang=/usr/lib64/erlang/usr/include --with-js-lib=/usr/local/lib/ --with-js-include=/usr/local/include/js/ #should output: You have configured Apache CouchDB, time to relax.
[ec2-user@ip ~]$ make
[ec2-user@ip ~]$ make test
[ec2-user@ip ~]$ make install

Note: you can of course replace 1.3.1 tag with the latest stable version if there’s any.

Hey, we’r almost done, lets configure the environment.

Create a couch user

For security reasons, create a dedicated couch user and correct files ownership and permissions:

1
2
3
4
5
6
7
8
9
[ec2-user@ip ~]$ sudo adduser -r --home /usr/local/var/lib/couchdb -M --shell /bin/bash --comment "CouchDB Administrator" couchdb
[ec2-user@ip ~]$ sudo chown -R couchdb:couchdb /usr/local/etc/couchdb
[ec2-user@ip ~]$ sudo chown -R couchdb:couchdb /usr/local/var/lib/couchdb
[ec2-user@ip ~]$ sudo chown -R couchdb:couchdb /usr/local/var/log/couchdb
[ec2-user@ip ~]$ sudo chown -R couchdb:couchdb /usr/local/var/run/couchdb
[ec2-user@ip ~]$ sudo chmod 0770 /usr/local/etc/couchdb
[ec2-user@ip ~]$ sudo chmod 0770 /usr/local/var/lib/couchdb
[ec2-user@ip ~]$ sudo chmod 0770 /usr/local/var/log/couchdb
[ec2-user@ip ~]$ sudo chmod 0770 /usr/local/var/run/couchdb

Starting Couch

1
2
[ec2-user@ip ~]$ sudo /usr/local/etc/rc.d/couchdb start
[ec2-user@ip ~]$ sudo /usr/local/etc/rc.d/couchdb status #should result: Apache CouchDB is running as process 3548, time to relax.

Check that things are working:

1
2
3
[ec2-user@ip ~]$ curl http://localhost:5984

{"couchdb":"Welcome","uuid":"6d597578de8744f92bdbc99c368c10ca","version":"1.3.1","vendor":{"name":"The Apache Software Foundation","version":"1.3.1"}}

Starting services when system starts

1
2
3
4
[ec2-user@ip ~]$ sudo ln -s /usr/local/etc/rc.d/couchdb /etc/init.d/couchdb
[ec2-user@ip ~]$ sudo chkconfig --level 345 couchdb on
[ec2-user@ip ~]$ service couchdb stop
[ec2-user@ip ~]$ service couchdb start

I suggest you to create a template at this stage, so you can simply create new instances whenever you need,

Hey, you are done, now it’s really time to relax :–)

Accessing EmberJS Controller From Different Scopes

Sometimes you want to use one ember controller from another, This simply can be done by “asking” ember access to the other controller:

1
2
3
4
5
6
7
App.PostController = Ember.ArrayController.extend({
    ...
})

App.CommentsController = Ember.ArrayController.extend({
  needs: "post"
});

Then you can simply use the Post controller in Comments’s template:

1
2
<!-- use comments template -->
{{ controllers.post }}

This works pretty nice, especially when you have nested routes (you surely want to display some data of the post when you are in the post’s comments context.),

But what if you need to access a controller outside of Ember’s scope?

For instance, you may have a websocket listening to a certain top level event and would like to update a certian controller when data is pushed,

You can use the container lookup to retrieve a controller instance:

1
2
3
4
5
// Somewhere out of Ember`s scope
ss.event.on('incomingComment', function(comment) {
    commentsController = App.__container__.lookup('controller:Comments')
    commentsController.pushObject(comment)
})