LoginSignup
38
40

More than 5 years have passed since last update.

ユーザーの行動履歴をMongoDBに保存する

Last updated at Posted at 2014-10-15

Railsのアプリケーションを作っているのですが、ユーザーの使用履歴とかを一覧表示したい、という仕様がありまして。
ユーザーがどのページを表示したとか、何を更新したとか等の情報を逐一保存しておきたいと。

DBはMySQLを使っているのですが、行動履歴みたいな情報をRDBにいちいち格納するのはパフォーマンス的にもちょっと心配だし、
削除もしない、どんどん溜めてくデータなので、KVSに入れるのはどうかな、と思いつきました。

で、やってみました

環境

  • MacOSX Lion
  • Ruby 2.0
  • Rails 4.0

MongoDBのインストール

手元のMacOSにMongoDBをインストールします。
外部のサーバーにインストールする場合は、こちらの記事をどうぞ。

CentOSにMongoDBをインストールして外部から接続できるようにする

MacOSにはHomebrewでインストールします。

brew install mongodb

# インストール完了後のメッセージに従って、以下のコマンドを実行
ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
mongo --version
 => MongoDB shell version: 2.6.4

RailsアプリからMongoDBに更新する

RailsにMongoDB用gemを追加

bson_extを入れないと、後の"config.mongoid.logger"でundefined methodエラーが出ました。

Gemifle
gem "mongoid"
gem "bson_ext"

インストール

bundle install --path .bundle

設定ファイルを作成。中身はそのままでOKです。

rails g mongoid:config
 =>create  config/mongoid.yml

設定保存用モデルを定義

デフォルトのDBがRDBになっている場合、MongoDBへ接続するmodelをgenerateするには下記のようにします。

rails g mongoid:model action_log

modelを編集して必要なfieldを定義します。

app/model/action_log.rb
class ActionLog
  include Mongoid::Document

  field :datetime, type: DateTime
  field :user_id, type: String
  field :user_name, type: String
  field :controller, type: String
  field :method, type: String
  field :body, type: String
  field :delete, type: Boolean
end

mongoDBだとdb:migrateする必要が無いのが嬉しいですね。
早速更新してみましょー。
まずはrails consoleからテスト。

irb(main):002:0> ActionLog.create!(datetime:Time.now, user_id:0, user_name:"jacoyutorius", body:"test")

=> #<ActionLog _id: 543df2987975746196000000, datetime: 2014-10-15 04:05:43 UTC, user_id: "0", user_name: "jacoyutorius", controller: nil, method: nil, body: "test", delete: nil>

無事更新できました。

ユーザーの各アクションを残したい

さて。
元々の仕様を思い出すと、「ユーザーの行動履歴を採りたい!」というのが始まりでした。
今回はcontrollerの各アクションが呼ばれる際のパラメータやログインユーザーをMongoDBに保存することで対応しようと思います。

各コントローラにずらずらと同じコードを書くのはDRYでないので、concernsを使います。

app/controllers/concerns/log_monger.rb
module LogMonger
  extend ActiveSupport::Concern

  included do 
      before_action :save_log

      def save_log
        ActionLog.create!(
          datetime: Time.now,
          user_id: 1,
          user_name: "jacoyutorius",
          method: params[:method],
          controller: params[:controller],
          body: params,
          delete: false
          )
      end

    end
end

controllerに飛ばされてくるparamsもまるまるbodyに格納してます。
あとは各コントローラでincludeします。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  include LogMonger

# -(省略)-
end

あとはRailsアプリを起動して適当にいじってみましょう。
MongoDBにはこんな感じで保存されます。

irb(main):005:0> ActionLog.first
=> #<ActionLog _id: 543deed77975745d73000000, datetime: 2014-10-15 03:49:43 UTC, user_id: "1", user_name: "jacoyutorius", controller: "admin/top", method: nil, body: "{\"controller\"=>\"top\", \"action\"=>\"index\"}", delete: false>

できました!

(2014.10.17 追記)

ActiveRecordとMongoidを併用している場合、ActiveRecordでmigrationコマンドを実行した場合に、"error mongoid [not found]"というエラーが出るようになりました。
この場合は、

rails g active_record:migration AddHoge

ActiveRecordを使うよう明示的に指定してやるとmigrationが作成できます。
こちらの記事を参考に解決しました。

mongoidとactiverecordが併存する場合のmigration

(さらに追記)

上記の対応だと、scaffoldの時に同じくmongoidが使われてしまう。
最終的にはapplication.rbでgeneratorの設定を定義しておくのが良いみたい。

application.rb
class Application < Rails::Application
  config.generators do |g|
    g.orm :active_record
  end
end

参考

mongoidバッドノウハウ集

バッドノウハウとありますが、特定の用途(今回でいえばログ取得)に絞った使い方であれば問題はないかなーと思っていますねー。

38
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
40