MongoMapper with Rails QuickStart

This assumes you have RVM Setup like I do.

I will typically start a new project off like so to create a new rails app (courtesy of RailsApps’ Rails Composer), where you can select such options as MongoDB (!):

cd ~/railsprojects
mkdir palette
cd palette
rvm use ruby-2.0.0@palette --ruby-version --create
gem install rails
rails new . -m https://raw.github.com/RailsApps/rails-composer/master/composer.rb -T -O
cd .
git add .
git commit -m "Initial rails generation"
rails s

Remove traces of mongoid from everywhere you find it… Might even be a file under spec/support/mongoid.rb
Add this to your Gemfile (as of March 2014, still need the beta tag for Rails4):

gem 'mongo'
gem 'mongo_mapper', :git => "git://github.com/mongomapper/mongomapper.git", :tag => "v0.13.0.beta2"
gem 'bson_ext'

In case you didn’t skip Active Record (-O), you might have to make the following changes in the config/application.rb file. Remove:

require 'rails/all'

And replace it with:

# Pick the frameworks you want:
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
# require "active_resource/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"

And configure some generators (and add the gems to your Gemfile):

   config.generators do |g|
      g.orm :mongo_mapper    # :active_record
      g.template_engine :erb # :haml
      g.test_framework :rspec, :fixture => true, :views => false
      g.fixture_replacement :factory_girl, :dir => "spec/factories"
    end

I like to use cucumber, rspec, factory girl or fabricator… RailsComposer should have set these up for you.

If you chose to use cucumber, your features/support/env.rb might have a reference to mongoid that needs to look like this instead:

# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
begin
  DatabaseCleaner[:mongo_mapper].strategy = :truncation
rescue NameError
  raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end

If you have an existing rails app with Active Record, you may have to comment out some other settings:

config/environments/development.rb

#config.active_record.mass_assignment_sanitizer = :strict
#config.active_record.auto_explain_threshold_in_seconds = 0.5

config/application.rb

#config.active_record.whitelist_attributes = true

Run

bundle install

Run the initializer:

rails g mongo_mapper:config

Which should create a config/mongodb.yml file (be sure to use your project name in place of palette), that should look something like this:

defaults: &defaults
  host: 127.0.0.1
  port: 27017
  options:
    w: 1
    pool_size: 1
    slave_ok: false
    ssl: false

development:
  <<: *defaults
  database: palette-development
  host: localhost
  logger: mongo

test: &test
  <<: *defaults
  database: palette-test
  host: localhost

production:
  <<: *defaults
  uri: <%= ENV['MONGOHQ_URL'] %>
  database: palette
  username: <%= ENV['MONGO_USERNAME'] %>
  password: <%= ENV['MONGO_PASSWORD'] %>

Add config/initializers/mongomapper.rb

# MongoMapper logging: control by 'logname' option in mongodb.yml
# if logname option omitted or set to 'none', disable logging.
# if logname set to 'rails' or 'default', use MongoMapper default log.
# otherwise, log to file log/_.log
logname = MongoMapper.config[Rails.env]['logger']

if logname.nil? || logname == 'none'
  MongoMapper.connection.instance_variable_set(:@logger, nil)
elsif logname != 'rails' && logname != 'default'
  logger = Logger.new(File.join(Rails.root, "/log/#{logname}_#{Rails.env}.log"), 'daily')
  logger.formatter = Logger::Formatter.new
  logger.datetime_format = "%H:%M:%S %Y-%m-%d"
  MongoMapper.connection.instance_variable_set(:@logger, logger)
end
# setup MongoMapper connection unless Rails app has already done so
unless MongoMapper::Connection.class_variables.include?(:@@database_name)
  env         = ENV['RAILS_ENV'] || 'development'
  config_file = "#{File.dirname(__FILE__)}/../mongodb.yml"
  MongoMapper.config = YAML.load(ERB.new(File.read(config_file)).result)
  MongoMapper.setup MongoMapper.config, env, :pool_size => 30, :pool_timeout => 5
end

#@@gridfs = Mongo::Grid.new(MongoMapper.database, 'attachments')

puts "Initialized: #{MongoMapper.database.name}"

I also have a config/initializers/mongodb.rb file:

# Set up database name, appending the environment name 
# (e.g., palette-development, palette-production)
MongoMapper.config = {
    Rails.env => { 'uri' => ENV['MONGOHQ_URL'] ||
        'mongodb://localhost/xxxxxxxx' } }
MongoMapper.connect(Rails.env)
name = "palette-#{Rails.env}"
if ENV['MONGOHQ_URL']
  uri = URI.parse(ENV['MONGOHQ_URL'])
  name = uri.path.gsub(/^//, '')
  puts "Env = #{ENV['MONGOHQ_URL']}; DB NAME: #{name}"
end
MongoMapper.database = "#{name}"

Now start things up in a couple of terminal windows:

mongod

And I like to run rspec and cucumber to be sure they are properly set up, and then run the rails server:

rspec
cucumber
rails s

Now would be a good time to commit 😉

If you want to add something real, here’s a quick way to test it all out (not for production):

rails g scaffold Book author title front_cover
http://localhost:3000/books

You should see a simple page where you can enter a new book!

(Note: when you go to update a book, you will need to change the controller code to be if @book.update_attributes(book_params) to get it to work…)

That’s it!


Leave a Reply