Friday, September 17, 2010

Ramaze and Mongo(DB and mapper): Day 2

1 comments
I've read on most documents before, that when using the NoSQL world it is still better to use it with RDBMS. Correct me if I'm wrong with this one, is it better to use them together or use them apart. If you have documents or links discussing this one, leave them in the comments, I'd love to read them. Also if so,
I'd like to know more is how should I separate them? Like what tables/collections would/should be this NoSQL or SQL?

So I tried testing with MongoDB and Sequel to make them play together and it was quite easy. If you have been using Ramaze before with Sequel, just do the same thing as before then just add configurations for the Mongo (which I also forgot to write configurations on my first part).

Configuration
with both MongoDB and Sequel
require 'rubygems'
require 'ramaze'
require 'yaml'

require 'bson'
require 'mongo_mapper'
require 'sequel'
require 'erubis'

MongoMapper.database = 'mongoplay'

Ramaze.options.layouts = '/view/layout'
Ramaze.options.mode = :dev

Ramaze.options.roots = [__DIR__] # Make sure that Ramaze knows where you are

Sequel.mysql(
  'mongoplay',
  :user => 'uname',
  :password => 'pword',
  :host => localhost
)

# Acquire controllers and models and other utilities
Ramaze.acquire 'util/*'
Ramaze.acquire 'model/base.rb', 'model/*'
Ramaze.acquire 'controller/base.rb', 'controller/*'
Ramaze.acquire 'config/routes.rb'


In the previous post on this topic, I was using a messaging/posting system and in here, I added a users table on a MySQL so we could tie some posts to a user if ever they wanted to register (I won't discuss here how to register/authenticate the user for now but you could use this link if so ever, that's what I used before). So the same model would apply ordinarily. I was using the user helper here.

User model
class User < Sequel::Model
  def self.register(email, password)
    User.create :email => email, :password => encrypt(password, salt), :salt => Digest::SHA1.hexdigest("--#{Time.now.to_f}--#{email}--")
  end

...


And now to insert posts and tie them to a certain user. You can also define the key in the message model or don't and you'd still insert them the same like so:
...
  if logged_in?
    Message.create :name => user.username, :body => request[:body], :user_id => user.id
  else
    Message.create :name => request[:name], :body => request[:body]
  end
...

And I just basically did the same with the comments section.

Now, now, to pull all the messages that a certain user has made:
class UsersController < Ramaze::Controller
  map '/users'

  def index(id)
    @msgs = Message.all :user_id => id.to_i
  end
end

If ever you were using a different model, just query first in the SQL table then query in the Mongo or vice-versa. :D

Wednesday, September 8, 2010

Ramaze and Mongo(DB and mapper): Day 1

0 comments
Edit ** I forgot to mention here how you would write a configuration file but you can check out my next post which mentions a small config for mongoDB and also for Sequel.

Okay. So day 1. I've chosen to use MongoMapper for now over the other two I've provided last post. MongoMapper is quite good, I haven't read/delved into their code but he said it was readable so looking forward to it. I just hope they don't make MongoMapper too rails-specific.

Okay, so moving on. I've started with the basics of most apps that is "Inserting data" on a "Collection". And having a "One to Many" relationship. This is just a basic app where you could post and comment to demonstrate. I assume here that you already have working applications and just want to start out using MongoDB.

The model would look like this.
Message Model
class Message
  include MongoMapper::Document

  key :name, String, :require => true
  key :body, String, :require => true
  timestamps! # This would create a "created_at" and "updated_at" keys on create

  many :comments
end

Take note that I have defined keys in the model. The keys can have typecast but it doesn't require you to have one. Also, you need not to define every key in the model as documents are schema-less, that's also one of the reasons of using MongoDB (unkown unknowns).

So for example you have a key :blah.
Test Model
class Test
  include MongoMapper::Document

  key :blah
end
Test.create :blah => 42
# => { "_id" : ObjectId("..."), "blah" : 42 }

Test.create :blah => "the answer"
# => { "_id" : ObjectId("..."), "blah" : "the answer" }

Test.create :blah => 42, :answer => "ultimate question"
# => { "_id" : ObjectId("..."), "blah" : 42, "answer" => "ultimate question" }

Okay. Going back to inserting records (but I think I've shown that already in the test). I only have basic information for now but here is a snippet of posting.
  def post
    if request.post?
      Message.create :name => request[:name], :body => request[:body]
      redirect r(:/)
    end
  end

Upon posting a message here, the data would look something like this.
{ "_id" : ObjectId("..."), "name" : "Post 2", "created_at" : "Tue Sep 07 2010 18:31:45 GMT 0800 (PHT)", "body" : "Test Body!", "updated_at" : "Tue Sep 07 2010 18:31:45 GMT 0800 (PHT)" }
Now I'd like to step on to relations, embedded documents.
Did you notice the last line before ending the MessageModel? It is a many relationship to comments. A comment model would look like this:
Comment Model
class Comment
  include MongoMapper::EmbeddedDocument

  key :name, String, :require => true
  key :body, String, :require => true
end

Note on the line 2 EmbeddedDocument would embed this document on the Message document. To try it out:
Per post snippet
  def posts(id = nil)
    id = id || request[:id]
    redirect r(:/) unless @msg = Message.find(id)

    if request.post?
      @msg.comments << Comment.new(:name => request[:name], :body => request[:body])
      @msg.save
    end
  end

This would produce a record like this
{ "_id" : ObjectId("4c8618b6be9294085d000001"), "name" : "Post 3", "created_at" : "Tue Sep 07 2010 18:49:26 GMT 0800 (PHT)", "comments" : [
    {
        "name" : "Tester",
        "body" : "Comment Yah!",
        "_id" : ObjectId("4c862781be929409d100000a")
    }
], "body" : "Another test body!", "updated_at" : "Tue Sep 07 2010 19:52:33 GMT 0800 (PHT)" }

Then when you pull the data from the "Per post snippet". You could iterate on the comments like so:
  <% @msg.comments.each do |c| %>
    <%= c.name %><br />
    <%= c.body %><br />
  <% end %>

This app and idea is far from perfect as it would still require validations and some form of filter to remove scripts but you get the gist of it. Also, I didn't include the views as I haven't written them completely as well, they are just basic forms with inputs and textareas and iterations for display but I think you all get what they would look like. If you need to see it, post a comment and I'll email it to you.

I don't know if I have written it awesome for now but I would like to hear how others are doing with Ramaze with MongoDB and MongoMapper.

Also, here is a complete code of the controller:
class MessagesController < Ramaze::Controller
  map '/'

  def index
    @msgs = Message.all
  end

  def post
    if request.post?
      Message.create :name => request[:name], :body => request[:body]
      redirect r(:/)
    end
  end

  def posts(id = nil)
    id = id || request[:id]
    redirect r(:/) unless @msg = Message.find(id)

    if request.post?
      @msg.comments << Comment.new(:name => request[:name], :body => request[:body])
      @msg.save
    end
  end
end

Monday, September 6, 2010

MongoDB start!

0 comments
I'll be playing around with MongoDB in the coming years and I think changing to this schema-less style works.

Installation


I've followed this link to install MongoDB on Snow Leopard. If you happen to get some errors here, make sure that all paths stated in the that document are created or else you'll get nasty errors. I was trying to mimic the errors I had before but I can't seem to get them again. Anyway, afterward, install the ruby driver to use here.

And now I'm looking at some mappers to use. I'm looking at MongoMapper or Candy or looking also at mongomatic while looking at tutorials and documents to play with mongoDB.

If you guys have any suggestions to help me out, please post on the comments.

Manipulating HTML checkbox using jQuery

0 comments
A small simple example or tutorial on how to manipulate HTML checkboxes with javascript with the help of jQuery (v1.4.2).

Here, I've given a sample on how to
  • select (check) checkboxes
  • deselect (uncheck) checkboxes
  • reverse select (check/uncheck)
  • do something with your selected checkboxes

Hope anyone finds it useful as I have.

Here is the HTML of the selectors and the group of checkbox. A textbox is written below as I will use it to sample what you have selected.
<div>
  <a id="select_all">Select all</a> | <a id="deselect_all">Deselect all</a> |
  <a id="reverse_select">Reverse</a> | <a id="submit_select">Submit</a>
</div>
<ul id="checkbox_container">
  <li>
    <input id="checkbox_1" type="checkbox" value="1" />
    <label for="checkbox_1">Checkbox 1</label>
  </li>
  <li>
    <input id="checkbox_2" type="checkbox" value="2" />
    <label for="checkbox_2">Checkbox 2</label>
  </li>
  <li>
    <input id="checkbox_3" type="checkbox" value="3" />
    <label for="checkbox_3">Checkbox 3</label>
  </li>
  <li>
    <input id="checkbox_4" type="checkbox" value="4" />
    <label for="checkbox_4">Checkbox 4</label>
  </li>
</ul>
<input id="write_to_me" type="text" />

Here is the Javascript (jQuery) to use.
$(document).ready(function() {
  $("#select_all").click(function() {
    $("#checkbox_container").find(':checkbox').attr('checked', 'checked');
  });

  $("#deselect_all").click(function() {
    $("#checkbox_container").find(':checkbox').removeAttr('checked');
  });

  $("#reverse_select").click(function() {
    $("#checkbox_container").find(':checkbox').each(function() {
      if (this.checked)
        $(this).removeAttr('checked');
      else
        $(this).attr('checked', 'checked');
    });
  });

  $("#submit_select").click(function() {
    checks = new Array();
    $("#checkbox_container").find(':checked').each(function() { checks.push($(this).val()); });
    $("#write_to_me").val(checks.join(','));
  });
});

Good luck!

Saturday, September 4, 2010

Just a quick update on Traxier

0 comments
Traxier is having a party at Las Vegas at the Palms today and tomorrow their time.

Thursday, September 2, 2010

Traxier's been posted at CNBC

0 comments
Yey!! We've been posted to news already at CNBC. Check out this link to see the news. Hehe! See yah there.