Rails3.1 使用mongodb学习笔记之mongo_地图er

Rails3.1 使用mongodb学习笔记之mongo_maper
根据官网的提示按照下面步骤依次进行,官网上的介绍文章用的是mongo_mapper但是我在网上查资料的时候发现很多人都是推荐mongoid的,本着学习,多学一点没坏处的想法,就硬着头皮弄了一遭,过几天再试一试mongoid:
安装rails
gem install rails

配置应用程序
很重要的一步就是要跳过这个active-record
rails new project_name --skip-active-record

如果是没有进行上一步而直接创建了rails项目,可以通过修改 config/application.rb 文件

#  require "rails/all" # 删除掉

# 添加下面
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"


同时要确保generate命令,不要去对对象关联active_record的orm

# Configure generators values. Many other options are available, be sure to check the documentation.
# config.generators do |g|
#   g.orm             :active_record
#   g.template_engine :erb
#   g.test_framework  :test_unit, :fixture => true
# end



安装gem初始化数据库

Gemfile中添加
source 'http://gemcutter.org'
require 'rubygems'
require 'mongo'
gem "rails", "3.1.0"
gem "mongo_mapper"

接下来运行指令安装gem
bundle install

如果提示没有bundle那么请先安装
gem install bundle


数据库:
创建文件config/initializers/mongo.rb添加内容:

MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
MongoMapper.database = "project_name_#{Rails.env}"

if defined?(PhusionPassenger)
   PhusionPassenger.on_event(:starting_worker_process) do |forked|
     MongoMapper.connection.connect if forked
   end
end


测试配置

创建文件 lib/tasks/mongo.rake 添加内容:

namespace :db do
  namespace :test do
    task :prepare do
      # Stub out for MongoDB
    end
  end
end


--------------------------------
中间遇到的问题以及解决过程

问题一、运行rails s ,出现错误提示:
**Notice: C extension not loaded. This is required for optimum MongoDB Ruby driver performance.
  You can install the extension as follows:
  gem install bson_ext

  If you continue to receive this message after installing, make sure that the
  bson_ext gem is in your load path and that the bson_ext and mongo gems are of the same version.

gems/ruby-1.9.2-p180/gems/execjs-1.3.0/lib/execjs/runtimes.rb:50:in `autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
	from /home/chinacheng/.rvm/gems/ruby-1.9.2-p180/gems/execjs-1.3.0/lib/execjs.rb:5:in `<module:ExecJS>'
	from /home/chinacheng/.rvm/gems/ruby-1.9.2-p180/gems/execjs-1.3.0/lib/execjs.rb:4:in `<top (required)>'


提示缺少gem包
 gem install bson_ext

安装之后,再运行,仍然出现上面这个错误
在Gemfile中添加
gem "bson_ext"

执行rails s
**Notice: C extension not loaded 这个问题就不存在了

还剩下JavaScript runtime这个错误,查了一下原因是:
Windows下默认有Javascript引擎,所以window下不会有这个错误。Linux下才有这个错误,一般只要第一个项目安装即可,以后的项目不用重复安装。
而且这个错误是由development环境中的assets包引起的,注释掉
# Gems used only for assets and not required
# in production environments by default.
#group :assets do
#  gem 'sass-rails', "  ~> 3.1.0"
#  gem 'coffee-rails', "~> 3.1.0"
#  gem 'uglifier'
#end

就不用安装’execjs’和’therubyracer’了。
当然这不是一个好办法
如果不注释,需要在Gemfile中添加
gem 'therubyracer'
gem 'execjs'

或者是安装一个Node.js

问题二:配置文件中hash的问题
ps:关于hash,因为工作原因,我本地既有ruby1.8又有ruby1.9
这个config/initializers/wrap_parameters.rb文件,如果是在ruby1.8.7中会出现如下错误:
 syntax error, unexpected ':', expecting kEND (SyntaxError)
  wrap_parameters format: [:json]

这个在ruby1.9.2环境中是没问题的
1.8环境下需要改成
wrap_parameters :format=>[:json]


另外session_store.rb这个文件中也会出现这个类似的问题:
 
syntax error, unexpected ':', expecting $end (SyntaxError)
...ion_store :cookie_store, key: '_project_name_session'

同理在1.9中没问题,1.8中要改成:key=>'_project_name_session'

上面这个问题突出的问题是:ruby1.8于ruby1.9在hash定义上出现的变化

#新的语法
h = { a: 1, b: 2 }# 

#旧的语法
h = { :a=> 1, :b=>2 }# 返回{:a=>1, :b=>2}

1.9.2同时兼容以前1.8.7的写法

----------------------------------------
接下来继续做那个demo

首先做一下首页的显示
运行指令
rails g controller index

创建index的控制器以及其他代码

先写测试

在控制器的测试文件中添加

 require 'test_helper'
 class IndexControllerTest < ActionController::TestCase
   test "access the index page" do
      get :index
      assert_response 200
   end
 end

运行,肯定跑不通,写代码来实现功能

删除public下面的index.html文件
配置以下路由,指定新的主页路径
root :to=>'index#index'


在IndexController中添加主页action
  class IndexController < ApplicationController
     def index
     end
  end

在app/view/index/下面添加index.erb文件

运行rake test,显示错误
test_helper.rb:3:in `<class:TestCase>': undefined method `fixtures' for ActiveSupport::TestCase:Class (NoMethodError)

这是测试用例的问题
把test_helper.rb中调用测试用例的代码注释掉
# fixtures :all

再次运行测试rake test

IndexControllerTest
     PASS test_access_the_index_page (0:00:00.334)
Finished in 0.335200 seconds.
1 tests, 1 passed, 0 failures, 0 errors, 0 skips, 1 assertions

访问主页成功

ps:上面的controller基本上跟mongo没啥关系,但是考到功能测试出现的这fixtures还是把这个放上来了

模型
创建一个名为user的model:执行命令
rails g model topic --skip-migration  --orm=mongo_mapper

orm这个参数如果不写,会出现这个错误
No value provided for required options '--orm'

执行完成之后显示生成的文件:
      invoke  mongo_mapper
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml

如果不想每一次都写这个--orm
在config/application.rb中添加:

config.generators do |g|
  g.orm :mongo_mapper
end


user.rb代码
class User
  include MongoMapper::Document
  key :name, String
  key :age, Integer
end

user_test.rb代码

# encoding: utf-8
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "new user test" do
    assert_equal User.count,0
    assert_difference "User.count",1 do
      User.create(:name=>"王华",:age=>18)
    end
    user = User.last
    assert_equal user.name, "王华"
    assert_equal user.age, 18
  end


运行单元测试
rake test:units 发现错误
Errors running test:units!
查看堆栈得到信息
** Invoke test:units (first_time)
** Invoke test:prepare (first_time)
** Invoke db:test:prepare (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:test:prepare
rake aborted!
Set config before connecting. MongoMapper.config = {...}


提示在链接之前先配置:
project_name$ script/rails generate mongo_mapper:config
      create  config/mongo.yml


此配置文件的内容是:


development:
  host: 127.0.0.1
  port: 27017
  database: project_name_development

test:
  host: 127.0.0.1
  port: 27017
  database: project_name_test

# set these environment variables on your prod server
production:
  host: 127.0.0.1
  port: 27017
  database: project_name
  username: <%= ENV['MONGO_USERNAME'] %>
  password: <%= ENV['MONGO_PASSWORD'] %>


rake test;units是没有问题了

UserTest
     PASS test_new_user_test (0:00:00.333)

Finished in 0.469750 seconds.

1 tests, 1 passed, 0 failures, 0 errors, 0 skips, 4 assertions



另外还写了一个users_controller的增删该查以及它的测试,跟mysql关联的写法没有任何区别,完全一样。很顺利的通过,剩余一个测试用例的问题