El SysAdmin del 3er Mundo

todo lo que expliqué mientras nadie prestaba atención

rails con mongodb

| Comments

Dicen que “en el mundo”, las bases de datos NoSQL están muy de moda…

Recién estuve pinchando ArangoDB y la experiencia fue traumática. Hay que reconocer que tiene potencial; pero aún no está listo. Finalmente, después de mucho rodar (Casandra y Redis) di con MongoDB. La instalación de MongoDB es tan sencilla como mandarlo a instalar con tu manejador de paquetes, así que no cubriré dichos detalles en este post.

El rollo viene con Rails… Resulta que al probar tal cual dice la documentación MongoMapper (la ORM de mongodb) a pesar de guiarte por los ejemplos al pie de la letra; NO PINCHA.

Al principio pensé que era corte con ActiveRecord, pues al quitarlo; por lo general a Rails le da una pataleta. Por suerte, este no es el caso.

MongoMapper está BIEN escrito pero MAL documentado

Todo parece indicar que a la documentación le faltan algunos detallitos. Bueno comenzamos. Creamos un proyecto SIN ActiveRecord (que dolor).

rails new fulanito -O -T

El Gemfile me quedó así:

Gemfile
1
2
3
4
5
6
7
8
9
10
source 'file:///media/sdb1/ruby/repo/'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.8'

# Use jquery as the JavaScript library
gem 'jquery-rails'

gem 'bson_ext'
gem 'mongo_mapper'

Ahora creamos un fichero que garantiza la conexión a la base de datos. Creamos un initializer de pacotilla y le declaramos la base de datos. Miren que facilito.

config/initializers/database.rb

config/initializers/database.rb
1
MongoMapper.database = "fulanito-#{Rails.env}"

Note que “fulanito” es el nombre de la aplicación, usted póngale a su base de datos el nombre que desee.

Ahora viene un paso muy curioso. El fichero “config/database.yml” NO puede dejar de existir; pero sus valores deben estar vacíos. Solución, le metemos un yaml vacío.

config/database.yml
1
echo "---" > config/database.yml

Ahora bien, la documentación dice que debes poner

  config.gem 'mongo_mapper'

En el fichero config/environment.rb

¡LO CUAL NO ES VÁLIDO!

Eso va en config/application.rb

config/application.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
require File.expand_path('../boot', __FILE__)

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

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Fulanito
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    # config.time_zone = 'Central Time (US & Canada)'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    #config.i18n.default_locale = :es

    # AQUI ES DONDE VA ESO
    config.gem 'mongo_mapper'

  end
end

A este punto PINCHA, pero hay que escribir los modelos A MANO, ya que el scaffold te crea todo menos el modelo. Para que eso pinche, debemos activar el generador de códigos declarándole su nueva ORM en el fichero.

config/application.rb

config/application.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require File.expand_path('../boot', __FILE__)

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

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Fulanito
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    # config.time_zone = 'Central Time (US & Canada)'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de

    # AQUI ES DONDE VA ESO
    config.gem 'mongo_mapper'

    # AQUI DECLARAMOS LA ORM
    config.generators do |g|
         g.orm :mongo_mapper
    end

  end
end

Ahora hay otro palo con el update de los scaffold, y eso si, no tiene remiendo. Por ejemplo

scaffold
1
2
3
4
5
6
7
8
9
10
11
12
13
# PATCH/PUT /users/1
def update

  # el update, es borra y crea
  @user.destroy
  @user=User.create user_params

  if @user.save
    redirect_to @user, notice: 'User was successfully updated.'
  else
    render :edit
  end
end

A cada update le arreglas eso. SI, ya sé, está feo. Yo lo borro y lo vuelvo a crear, pero quizás a ti se te ocurra algo mejor.

Bueno ahora si, con eso todo se vuelve NoSQL y nuestro cerebro sigue siendo Rails…

Además, MongoMapper puede usarse fuera de Rails tranquilamente. Las dos simples lineas que componen nuestro initializer son más que suficiente para dejar a MongoMapper pinchando. Luego creas lo modelo y listo.

Happy coding!

Si este artículo te resultó interesante, considere donar 0.09 BTC: 14iNmkfULf5jggumVh963kUg4UPScEZHgz

Comments