Wednesday, October 17, 2012

Derby.js – The Ready() Function, and Adding Client-Side Scripts to your App

I’ve found a neat feature of derby dealing with the ready() function.
I’ve been creating a derby app, and in my application I need to load up a client-side calendar. With a standard HTML web page this is straightforward thing to do. On the page you wanted the calendar, you would include the client js for the calendar, some code to load it, and that would be that.
Derby introduced some complexity to this relatively simple task.
On my first attempt, I put my scripts in the section of the page that I needed the calendar on. I added a script to load the calendar as well. When I went to the url of the page, it loaded immediately. Success! (I thought).
Then I clicked a link away from my calendar, and then clicked back. No calendar.
What happened? When I loaded the link originally, the page was rendered from the server. The second time, the page was rendered client side. Something wasn’t working with loading the calendar on the client-side render.
You need a place to put your code that guarantees that it will load on the client-side. Theapp.ready() function is designed to handle this scenario.
What is the purpose of the app.ready() function? From the derby documentation:
Code that responds to user events and model events should be placed within the app.ready() callback. This provides the model object for the client and makes sure that the code is only executed on the client.
This function is called as soon as the Derby app is loaded on the client. Note that any code within this callback is only executed on the client and not on the server.
I’ve bolded the part I think is particularly important. This code is run as soon as the client is loaded. Which means if you have more than a single-page app, using app.ready() to load a feature might not work out.
So what to do? An undocumented feature of Derby – app.on().
What does it do? It allows you to load code AFTER a specific page has loaded. Which is exactly what I’m looking for.
So here’s what I ended up writing in my app.ready():
1
2
3
4
app.on('render:calendar', function(ctx) {
  logger.log("rendering calendar client-side...");
  new Timeline("timeline", new Date());
});
In this example this code will run after rendering the calendar view. On the Calendar page, there is a script block which loads the Timeline function.
After writing this code, I tried my page again. Still no luck. I wasn’t getting the calendar to load on both the client and server load.
On a lark, I moved the block containing my Timeline javascript to my index view, and tried again. Success.
Which makes sense. If you are rendering pages via the client side load, additional resources aren’t going to be loaded. So by putting my script into the index view, it’s unfortunately loaded for all my pages, but at least it’s available for both the client and server side rendering of my cool control.

Thursday, September 6, 2012

Setting up MongoDB to work with Derby.js

This post is going to cover installing and configuring MongoDB to use with Derby.
If you’re reading this post looking to add model persistence to your Derby application but don’t know much about MongoDB, understanding MongoDB will help you understand Derby and the model system it uses.

What’s MongoDB?

From their website:
MongoDB (from “humongous”) is a scalable, high-performance, open source NoSQL database.
If you’ve never used MongoDB before, you should immediately go here. This is the easiest, fastest way to learn the basics of what mongo is and how it works. And it only takes about fifteen minutes. It’s even interactive to keep you from getting bored. Go give it a play.

Derby and MongoDB

Now that you have an idea about how MongoDB works, many of the conventions Derby uses for models should make sense. If you scan through the Derby Query Readme now, hopefully is makes a bit more sense (like where the term “gte” came from).

Installing MongoDB

If you still need to install MongoDB go here for downloads and installation directions.

Configuring Derby to use MongoDB

Now that you know about MongoDB, let’s get MongoDB set up to work with Derby. This is straightforward and takes about two minutes.
To add MongoDB to your Derby application, you’ll need to include the racer-db-mongopackage in your project.
Update your package.json file to look something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "name": "potluck",
  "description": "",
  "version": "0.0.1",
  "main": "./server.js",
  "dependencies": {
    "derby": "*",
    "derby-ui-boot": "*",
    "express": "3.0.0beta4",
    "gzippo": ">=0.1.7",
    "racer-db-mongo": "*" //this is the line. Glory in its beauty.
  },
  "private": true
}
Then, at the command prompt, update your project (and download the recently addedracer-db-mongo dependency) using the following command:
 npm update 
You’ll have to update your server configuration (by default in /lib/server/index.js) to use the new dependency. This requires TWO new lines of code
1
2
3
4
5
6
derby.use(require('racer-db-mongo')); // This line is new
 
app.createStore({
  listen:  server
, db:      {type: 'Mongo', uri: 'mongodb://localhost/database'} /* This line is new */
});
That’s all the changes you need to make to add MongoDB to your project. So why I’d bother with a blog post?

What About Troubleshooting?

Now, if you go and start your Derby application, you might see the following error:
Error: failed to connect to [localhost:27017]
Which means:
  1. You’ve installed the racer-db-mongo dependency correctly!
  2. You now need to:
    • Install MongoDB
    • Turn on MongoDB
    • OR Fix MongoDB
If you’ve forgotten to install Mongo, if you look around, you’ll probably find a link somewhere which will help you out.

Starting/Stopping/Statusing MongoDB

If you’ve installed Mongo, you have to start the service before Derby can use it. On Ubuntu, you start Mongo using the following command:
 sudo start mongodb 
Remember to stop Mongo later with:
 sudo stop mongodb 
If you’ve started Mongo, then loaded your Derby application, and you’re still getting an error, it’s possible that Mongo did not start correctly. Typing:
 sudo status mongodb 
will let you know if Mongo is running or not. If you’ve run the Mongo Start command, yet the status command is telling you that Mongo is stopped, the most likely cause is Mongo did not shut down gracefully last time it was run. You’ll have to go and repair your installation (luckily, this is pretty easy).

Repairing MongoDB

To repair your installation, run the following commands:
$ sudo rm /var/lib/mongodb/mongod.lock
$ sudo -u mongodb mongod -f /etc/mongodb.conf --repair 
The code above was taken from this great article
At this point, you should have a working copy on MongoDB along with a working integration with Derby. Congrats!

MongoDB is working great – now Derby hates me

If your application loads, but you’re getting a strange error whenever you add to a collection that looks something like this:
Error: No persistence handler for 
push(FIRST_WORD.SECOND_WORD, [object Object], 18) 
It means that you are pushing to the wrong portion on an model path. You can only use push to arrays, and arrays are not objects, and you can only use objects for the first and second words of your model path. In the case shown above, a push is attempting to be made to
 FIRST_WORD.SECOND_WORD 
which equates to
 FIRST_WORD.SECOND_WORD.push(object) 
which means SECOND_WORD is an array (which isn’t allowed).
If this last bit of explanation might have well been in Latin, check out this post. It’ll explain a little bit about how to declare models and what Derby is expecting you to do.
Unfortunately, you CAN use the second word of a model path as an array without persistence support. So this kind of bug will only surface once you’ve got MongoDB integrated with Derby.