Double Shot #659 »
Created at: 02.03.2010 13:00, source: A Fresh Cup, tagged: Double Shot aws erector flowdock github mongo ujs
I could use at least a small slowing-down of the treadmill for a day or two.
- How I reduced translation costs of 200 articles from $9000 to $46 - Second Life as an alternative to Mechanical Turk.
- Notes from a production MongoDB deployment - Some detailed stories from the trenches.
- Rapid prototyping with HAML, SASS and Ruby - A workflow for coming up with web site designs.
- Erector - Builder-like view framework for object-oriented HTML composition.
- ambitious_query_indexer - Another plugin for testing whether your Rails application needs more indexes.
- Flowdock Public Beta to launch - Our team has been using this tool, and it's been working well for us.
- Introducing GitHub Compare View - More analytic power from GitHub, who are clearly concentrating on feature differentiation these days.
- Unobtrusive, yet explicit - Jamis Buck tries to work out a useful pattern for UJS in Rails 3.
- S3Hub - Amazon S3 client for OS X.
more »
Double Shot #658 »
Created at: 01.03.2010 13:08, source: A Fresh Cup, tagged: Double Shot canable mongo rails ruby sinatra subversion
New months always hold so much promise.
- Warehouse -"A Web-based subversion browser that doesn't suck."
- Garbage Collection Slides from LA Ruby Conference - A good intro to a tough ruby topic, with pointers to some useful utilities.
- Great CS Program for GIrls Needs Funding - Another good cause that could use some of your hard-earned dollars.
- Using Sinatra to test remote services in Rails - Another testing idea from Elad Meidar.
- Canable: The Flesh Eating Permission System - John Nunemaker's take on authorization. Looks fairly similar to the way I've been handling it recently.
- rails_indexes - I think I mentioned this plugin for finding missing indexes before, but it came in handy this weekend so I'm mentioning it again.
- Support Details - A way to quickly query a user's machine for things like OS, Browser, IP address, and color depth.
- Migrations with Mongo (and MongoMapper) - Otherwise known as "mongrations".
- Lesson from Madlibs Signup Fad: Do Your Own Tests - Amen.
more »
MongoMapper, The Rad Mongo Wrapper »
Created at: 27.06.2009 19:59, source: RailsTips - Home, tagged: database mongo mongomapper
In which I formally release MongoMapper, a high level wrapper similar to ActiveRecord, but for MongoDB.
A few weeks ago, I wrote about Mongo and how awesome it is. Towards the end of the article (and in the slideshow) I mentioned MongoMapper, a project I’ve been working on.
Over the past few weeks my buddies at Squeejee and Collective Idea have started using MongoMapper and they’ve helped me squash a few bugs and add a few features.
Despite the fact that I would call it far from finished, I’ve decided to release it in hopes that people can start playing with it, finding bugs, adding features and submitting pull requests. The documentation is sparse to none, but there are plenty of tests and the code is pretty readable, I believe.
Installation
# from gemcutter
gem install mongo_mapper
Usage
So how do you use this thing? It’s pretty simple. MongoMapper uses a default connection from the Ruby driver. This means if you are using Mongo on the standard port and localhost, you don’t have to give it connection information. If you aren’t, you can do it like this:
MongoMapper.connection = Mongo::Connection.new('hostname')
Connection accepts any valid Mongo ruby driver connection. The only other setup you need to do is to tell MongoMapper what the default database is. This is pretty much the same as setting up the connection:
MongoMapper.database = 'mydatabasename'
These two operations only define the default connection and database information. Both of these can be overridden on a per model basis so that you can hook up to multiple databases on different servers.
Include Instead of Inherit
To create a new model, I went with the include pattern, instead of inheritance. In ActiveRecord, you would define a new model like this:
class Person < ActiveRecord::Base
end
In MongoMapper, you would do the following:
class Person
include MongoMapper::Document
end
Just like ActiveRecord, this makes assumptions. It assumes you have a collection named people. Oh, and the good news is you don’t need a migration for it. The first time you try to create a person document, the collection will be created automatically. Heck yeah! I mentioned that you can override the default connection and database on a per document level. If you need to do that, it would look like this:
class Person
include MongoMapper::Document
connection Mongo::Connection.new('hostname')
set_database_name 'otherdatabase'
end
Defining Keys
Each document is made up of keys. Keys are named and type-casted so you know your data is stored in the correct format. Lets fill out our Person document a bit.
class Person
include MongoMapper::Document
key :first_name, String
key :last_name, String
key :age, Integer
key :born_at, Time
key :active, Boolean
key :fav_colors, Array
end
Now that we have defined our schema, we can create, update and delete documents.
person = Person.create({
:first_name => 'John',
:last_name => 'Nunemaker',
:age => 27,
:born_at => Time.mktime(1981, 11, 25, 2, 30),
:active => true,
:fav_colors => %w(red green blue)
})
person.first_name = 'Johnny'
person.save
person.destroy
# or you could do this to destroy
Person.destroy(person.id)
Looks pretty familiar, eh? Where it made sense, I tried to stay close to ActiveRecord in API.
Validations
But wait you say, how do I validate my data? Well, you can do it pretty much the same way as ActiveRecord.
class Person
include MongoMapper::Document
key :first_name, String
key :last_name, String
key :age, Integer
key :born_at, Time
key :active, Boolean
key :fav_colors, Array
validates_presence_of :first_name
validates_presence_of :last_name
validates_numericality_of :age
# etc, etc
end
But, if you find that a bit tedious as I do, you can use some shortcuts that I’ve added in.
class Person
include MongoMapper::Document
key :first_name, String, :required => true
key :last_name, String, :required => true
key :age, Integer, :numeric => true
key :born_at, Time
key :active, Boolean
key :fav_colors, Array
end
Most of the validations from Rails are supported. I still need to build in support for validates_uniqueness of and some of the options that rails supports might not be right now, but it is a good first pass.
Callbacks
Did you hear that? I swear I just heard someone whisper about callbacks. Umm, yeah, we got that too. The good news? I just used ActiveSupport’s callbacks so they are identical to Rails and most of Rails defined callbacks are supported such as before_save and the like.
Embedded Documents
So the cool thing about Mongo is that you can embed documents in other documents. Let’s say our person has multiple addresses. To handle that, we would create an embedded address document to go along with our person document.
class Address
include MongoMapper::EmbeddedDocument
key :address, String
key :city, String
key :state, String
key :zip, Integer
end
class Person
include MongoMapper::Document
many :addresses
end
Now we can add addresses to the person like so:
person = Person.new
person.addresses << Address.new(:city => 'South Bend', :state => 'IN')
person.addresses << Address.new(:city => 'Chicago', :state => 'IL')
person.save
Doing this actually saves the address right inside the person document. Yep, no joins. Yay! Cheers resound from the heavens! You can even query for documents based on these embedded documents. For example, if you wanted to find all people that are in the city Chicago, you could do this:
Person.all(:conditions => {'addresses.city' => 'Chicago'})
Finding Documents
The find API is very similar to AR as well. Below are a bunch of other examples:
Person.find(1)
Person.find(1,2,3,4)
Person.find(:first)
Person.first
Person.find(:last)
Person.last
Person.find(:all)
Person.all
Person.all(:last_name => 'Nunemaker', :order => 'first_name')
For more information about how to provide criteria to find, you can see the stuff covered in the finder options. If you need to, you can even throw custom mongo stuff into the mix and it just gets passed through to the mongo ruby driver (ie: $gt, $gte, $lt, $lte, etc.).
Conclusion
We take ActiveRecord for granted. It really has a lot of handy features and does a pretty good job at modeling our applications. I never realized how much it does, until I decided to create MongoMapper. That said, the experience has been fun thus far and I’m excited to see what people use it for.
There is a ton more I could talk about, but frankly, this article is long enough. Rest assured that I think Mongo is cool and that MongoMapper is headed in the right direction, but far from complete. I haven’t actually built anything with MongoMapper yet, but I will be soon. I’m sure that will lead to a lot of handy new features.
Any general discussion can happen in the comments below while they are open or over at the google group. If you find a bug or have a feature idea, create an issue at github.
more »
