Skip to content

Instantly share code, notes, and snippets.

@bitzesty
Created January 4, 2010 22:58
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save bitzesty/268948 to your computer and use it in GitHub Desktop.
Save bitzesty/268948 to your computer and use it in GitHub Desktop.
Getting up and running with MongoDB/MongoMapper
# config/enviroment.rb
config.gem 'mongo'
config.gem 'mongo_mapper'
# remove AR
config.frameworks -= [ :active_record, :active_resource ]
# config/initializers/mongodb.rb
include MongoMapper
db_config = YAML::load(File.read(File.join(Rails.root, "/config/mongodb.yml")))
if db_config[Rails.env] && db_config[Rails.env]['adapter'] == 'mongodb'
mongo = db_config[Rails.env]
MongoMapper.connection = Mongo::Connection.new(mongo['host'] || 'localhost',
mongo['port'] || 27017,
:logger => Rails.logger)
MongoMapper.database = mongo['database']
if mongo['username'] && mongo['password']
MongoMapper.database.authenticate(mongo['username'], mongo['password'])
end
end
ActionController::Base.rescue_responses['MongoMapper::DocumentNotFound'] = :not_found
# Used for image uploads
# CarrierWave.configure do |config|
# mongo = db_config[Rails.env]
# config.grid_fs_database = mongo['database']
# config.grid_fs_host = mongo['host'] || 'localhost'
# config.grid_fs_access_url = "gridfs"
# config.grid_fs_username = mongo['username']
# config.grid_fs_password = mongo['password']
# end
# It's also possible to define indexes in the the model itself; however,
# a few issues are being worked out still. This is a temporary solution.
# Comment.ensure_index([["story_id", 1], ["path", 1], ["points", -1]])
# MongoMapper.ensure_indexes!
# Handle passenger forking.
# if defined?(PhusionPassenger)
# PhusionPassenger.on_event(:starting_worker_process) do |forked|
# MongoMapper.database.connect_to_master if forked
# end
# end
# config/mongodb.yml
base: &base
adapter: mongodb
database: coolapp
#These are needed to authenticate with your db
#should it run on another server
host: genesis.mongohq.com
username: your-username
password: your-password
development:
<<: *base
test:
<<: *base
database: coolapp-test
production:
<<: *base
gem install mongo_mapper
gem install mongo_ext #the c extensions (for production)
# lib/multi_parameter_attributes.rb
module MultiParameterAttributes
def attributes=(attrs)
multi_parameter_attributes = []
attrs.each do |name, value|
return if attrs.blank?
if name.to_s.include?("(")
multi_parameter_attributes << [ name, value ]
else
writer_method = "#{name}="
if respond_to?(writer_method)
self.send(writer_method, value)
else
self[name.to_s] = value
end
end
end
assign_multiparameter_attributes(multi_parameter_attributes)
end
def assign_multiparameter_attributes(pairs)
execute_callstack_for_multiparameter_attributes(
extract_callstack_for_multiparameter_attributes(pairs)
)
end
def execute_callstack_for_multiparameter_attributes(callstack)
callstack.each do |name, values_with_empty_parameters|
# in order to allow a date to be set without a year, we must keep the empty values.
# Otherwise, we wouldn't be able to distinguish it from a date with an empty day.
values = values_with_empty_parameters.reject(&:nil?)
if values.any?
key = self.class.keys[name]
raise ArgumentError, "Unknown key #{name}" if key.nil?
klass = key.type
value = if Time == klass
Time.zone.local(*values)
elsif Date == klass
begin
values = values_with_empty_parameters.collect do |v| v.nil? ? 1 : v end
Date.new(*values)
rescue ArgumentError => ex # if Date.new raises an exception on an invalid date
Time.zone.local(*values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
end
else
klass.new(*values)
end
writer_method = "#{name}="
if respond_to?(writer_method)
self.send(writer_method, value)
else
self[name.to_s] = value
end
end
end
end
def extract_callstack_for_multiparameter_attributes(pairs)
attributes = { }
for pair in pairs
multiparameter_name, value = pair
attribute_name = multiparameter_name.split("(").first
attributes[attribute_name] = [] unless attributes.include?(attribute_name)
attributes[attribute_name] << [ find_parameter_position(multiparameter_name), value ]
end
attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
end
def find_parameter_position(multiparameter_name)
multiparameter_name.scan(/\(([0-9]*).*\)/).first.first
end
end
# models/comment.rb
class Comment
# Class Configuration :::::::::::::::::::::::::::::::::::::::::::::
include MongoMapper::Document
# Attributes ::::::::::::::::::::::::::::::::::::::::::::::::::::::
key :message, String
key :message_html, String
key :user_id, ObjectId
key :username, String
timestamps!
# Validations :::::::::::::::::::::::::::::::::::::::::::::::::::::
validates_presence_of :message
# Assocations :::::::::::::::::::::::::::::::::::::::::::::::::::::
belongs_to :user
# Callbacks :::::::::::::::::::::::::::::::::::::::::::::::::::::::
before_create :set_username, :htmlify
after_create :increment_comment_count
private
def increment_comment_count
User.increment(user_id, :comment_count => 1)
end
def htmlify
self.message_html = RedCloth.new(message).to_html
end
def set_username
self.username = self.user.username
end
end
# models/user.rb
class User
# Class Configuration :::::::::::::::::::::::::::::::::::::::::::::
include MongoMapper::Document
devise :authenticatable, :recoverable, :rememberable
# Attributes ::::::::::::::::::::::::::::::::::::::::::::::::::::::
key :email, String
key :username, String
key :comment_count, Integer
key :encrypted_password, String
key :password_salt, String
key :reset_password_token, String
key :remember_token, String
key :remember_created_at, Time
key :sign_in_count, Integer
key :current_sign_in_at, Time
key :current_sign_in_ip, String
timestamps!
# Validations :::::::::::::::::::::::::::::::::::::::::::::::::::::
RegEmailName = '[\w\.%\+\-]+'
RegDomainHead = '(?:[A-Z0-9\-]+\.)+'
RegDomainTLD = '(?:[A-Z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
RegEmailOk = /\A#{RegEmailName}@#{RegDomainHead}#{RegDomainTLD}\z/i
validates_length_of :email, :within => 6..100, :allow_blank => true
validates_format_of :email, :with => RegEmailOk, :allow_blank => true
# Assocations :::::::::::::::::::::::::::::::::::::::::::::::::::::
many :comments
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment