18

2012/06

テストコードを書き始める前はじゃんじゃんprintしまくってログをみて実装していたのでガンガン出力されるデバッグ分が
色分けされてないとどうにも見分けがつかない状況だったので色分けできるようにしてみました。

class Logger
  class Formatter
    def call(severity, time, progname, msg)
      msg = msg.to_s.gsub(/(SELECT.+)/, "\033\[1;33m" + '[SQL] \1' + "\033\[0m")
      msg = msg.to_s.gsub(/(UPDATE.+)/, "\033\[1;34m" + '[SQL] \1' + "\033\[0m")
      msg = msg.to_s.gsub(/(DELETE.+)/, "\033\[1;35m" + '[SQL] \1' + "\033\[0m")
      msg = msg.to_s.gsub(/(INSERT.+)/, "\033\[1;32m" + '[SQL] \1' + "\033\[0m")

      case severity
        when "FATAL"
          # \033[#{esc};#{bg};#{fg}m hogehoge \033[0m
          "#{time.to_s(:db)} \033[1;33;41m[#{severity}]\033[0m #{msg}\n"
        when "ERROR"
          "#{time.to_s(:db)} \033[1;33;45m[#{severity}]\033[0m #{msg}\n"
        when "WARN"
          "#{time.to_s(:db)} \033[1;30;43m[#{severity}]\033[0m #{msg}\n"
        when "INFO"
          "#{time.to_s(:db)} \033[1;36;40m[#{severity}]\033[0m #{msg}\n"
        else
          "#{time.to_s(:db)} \033[1;34;40m[#{severity}]\033[0m #{msg}\n"
        end
    end
  end
end

■参照URL
http://api.rubyonrails.org/cla……ogger.html
http://blog.rantan.jp/archives/107

09

2012/06

RailsでBASIC認証をさせる

Railsで手っ取り早くBASIC認証させるためのメモ

class BasicController < ApplicationController

  before_filter :basicauth

  def basicauth
    name = 'hoge'
    password = 'hohohohoho'
    msg = 'please input basic auth'
    authenticate_or_request_with_http_basic(msg) do |n,p|

      File.open("#{Rails.root}/public/password.txt", "r") {|f|
        f.each_line do |line|
          arr = line.split(":")
          name = arr[0]
          password = arr[1]
          if n == name && p.crypt(password[0,2]) == password
            logger.debug("ok!!!")
          else
            return false
          end
        end
      }
    end
  end
end

うん、簡単ですね。Zendのときでもこんなに完結にはかけなかったものです。。

「authenticate_or_request_with_http_basic」すばらしい!!

02

2012/06

Railsはテーブルを作成するときの決まり事として「created_at」「updated_at」と作成されます。 しかし、既存テのーブル構成を変更しないで作成・更新日時のカラムを利用しようとしたとき不便なものがありますが、 以下の方法を実装すれば、既存のカラムを変更しなくてもそれがRailsもモデル作成・更新日時用のカラムとして 認識させてくれるのです。

module ActiveRecord
  module Timestamp
    private
    def timestamp_attributes_for_update #:nodoc:
      [:update_time, :update_date, :updated_at]
    end

    def timestamp_attributes_for_create #:nodoc:
      [:make_time, :create_date, :created_at]
    end
  end
end

enviroment.rbに記述して再起動すれば反映されているはずです。

04

2012/05

次は実際にソースをリモートに設置させるようにします。

このコマンドで必要最低限のファイルを自動で作成してくれます。

$ capify . 
$ emacs config/deploy.rb

その作成されたファイルを自分の環境に合わせて設定します。 以下だと、gitで管理しているソースをappユーザで配置します。

set :application, "hogeme"
set :repository,  "ssh://hogeme.git" # git
set :deploy_to, "/var/www/#{application}"
set :scm, :git

#set :user, "app"                                                                                                                                                                    
set :user, "nakaji"
set :use_sudo, false

role :web, "hoge.me"
role :app, "hoge.me"
role :db,  "hoge.me", :primary => true

デプロイの処理を行うコマンドです。

$ cap deploy:setup

このときリモート側でディレクトリがもろもろ作成されます

[remote] $ tree
.
├── releases
└── shared
    ├── log
    ├── pids
    └── system
$ cap deploy:update
[remote] $ tree
.
├── current -> /var/www/hogeme/releases/20120228170906
├── releases
│   └── 20120228170906
│       ├── Gemfile
│       ├── Gemfile.lock
・
・
・
└── shared
    ├── log
    ├── pids
    └── system

以上。

02

2012/03

会社でのデプロイツールといったらCapistranoのビルドを管理するWebistranoというツールを使って管理して、本番や開発環境に
ソースをデプロイする際には大変重宝してます。ボタン一つで指定された複数のサーバへ一気にソースをデプロイなんてできてしまいます。

とはいえ、裏側が対して分かってないので理解を深めるためにあえてCapistranoを利用してデプロイなんかしてみようと思います。

とりあえず、作業用ディレクトリ作成してデプロイする内容のファイル「Capfile」を作成します。ここでデプロイするときに必要な作業を記述するみたい。今回はリモートにファイルを置くっていう作業。

$ mkdir capistrano && cd capistrano
$ emacs Capfile

set :user, 'nakaji'
task :stamp, :hosts => "hoge.me" do
  run "touch /var/www/hoge.me/test"
end

実際に実行してみます。
リモートに指定ファイルが作成されていればOK!
あ、sshで接続しにいくので公開鍵の設定はあらかじめ設定しておいてくださいな。

$ cap stamp
  * executing `stamp'
  * executing "touch /var/www/hoge.me/test"
    servers: ["hoge.me"]
    [hoge.me] executing command
    [hoge.me] sh -c 'touch /var/www/hoge.me/test'
    command finished in 83ms

次はソースを展開してデプロイまでやってみます。

■参考URL
https://github.com/peritor/webistrano

17

2012/02

なんか神経使った。Railsはいちいちつまずく。
デフォルトだとロケールも英語になっていてなんの問題もないけど、フォーマット変更したり、日本語にしたりするとさらに追加の設定が必要になったのでめも。

最初はデフォルトのロケールを日本語にしているとエラーが発生してたので調査しました。
yaml側でどうも解析できていないみたいだったのでboot.rbに明示的に記述を足してライブラリを読み込めるように
しました。

# confg/application.rb
config.i18n.default_locale = :ja
# config/boot.rb
require 'yaml' # この行を追加
YAML::ENGINE.yamler= 'syck' # この行を追加

そんでもって日付のフォーマットを変更してみる

# config/locale/ja.yml
ja:
  date:
    order: [ :year, :month, :day ]
  datetime:
    order: [ :year, :month, :day, :hour, :min ]
# views/hoge/_form.html.erb
<%= f.datetime_select :disp_date, :use_month_numbers => true %>

うまくいきました。

■参考URL
http://stackoverflow.com/quest……yamlengine

15

2012/02

Railsでsorceryを使ってログイン処理を実現してみることにします。

まずはMysqlを理由するのでそれに関連したプラグインもいれてきます。
Gemfileに必要なプラグインを記述

gem 'mysql2'
gem 'sorcery'
gem 'refinerycms'
bundle install

DBの設定を行います

development:
  adapter: mysql2
  database: gifanime
  pool: 5
  timeout: 5000
  encoding: utf8

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: mysql2
  database: gifanime
  pool: 5
  timeout: 5000
  encoding: utf8

production:
  adapter: mysql2
  database: gifanime
  pool: 5
  timeout: 5000
  encoding: utf8

とりあえず、WEBサーバが動作するようにUnicornの設定をします。(内容はとりあえず、動作する目的で記述しているのであまりつっこまないでください)

# -*- coding: utf-8 -*-
# ワーカーの数
worker_processes 2

# capistrano 用に RAILS_ROOT を指定
app_path = "/Users/nakajimadaichi/develop/gifanime/"
working_directory app_path

# ソケット
listen  '/tmp/unicorn.sock'

# ログ
rails_env = ENV['RAILS_ENV'] || 'production'
if rails_env == 'production'
  stderr_path 'log/unicorn.log'
  stdout_path 'log/unicorn.log'
else
  # stdout
end

# ダウンタイムなくす
preload_app true

before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{ server.config[:pid] }.oldbin"
  unless old_pid == server.pid
    begin
      # SIGTTOU だと worker_processes が多いときおかしい気がする
      Process.kill :QUIT, File.read(old_pid).to_i
      rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

前回の設定をちょっとかえてて、環境によってエラー出力をファイル出力か標準出力ぐらいのことしてます。
最後に起動してこんなふうに出力すればとりあえず完了。。

$ unicorn_rails -c config/unicorn.rb -E development -p 5000
I, [2012-02-12T19:35:14.296704 #4448]  INFO -- : unlinking existing socket=/tmp/unicorn.sock
I, [2012-02-12T19:35:14.297074 #4448]  INFO -- : listening on addr=/tmp/unicorn.sock fd=5
I, [2012-02-12T19:35:14.298091 #4448]  INFO -- : listening on addr=0.0.0.0:5000 fd=6
I, [2012-02-12T19:35:14.298290 #4448]  INFO -- : Refreshing Gem list
I, [2012-02-12T19:35:16.681432 #4448]  INFO -- : master process ready
I, [2012-02-12T19:35:16.694516 #4477]  INFO -- : worker=0 ready
I, [2012-02-12T19:35:16.698188 #4478]  INFO -- : worker=1 ready

次はsorceryのインストールです。

# デフォルトのインストール
rails generate sorcery:install
# ユーザのリソースを作成
rails g scaffold User username:string email:string crypted_password:string salt:string
# DBは婦負
rake db:migrate
# セッション用のコントローラ作成
rails g controller UserSessions new create destroy

あとはsorceryが公開されているgithubのwikiをみて写経していきます。

# views/user_sessions/new.html.erb
<%= form_for(@user) do |f| %>
  <% if @user.errors.any? %>
    

<%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:

    <% @user.errors.full_messages.each do |msg| %>
  • <%= msg %>
  • <% end %>
<% end %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
<%= f.submit %>
<% end %>
# models/user.rb
class User < ActiveRecord::Base
  authenticates_with_sorcery!
  #attr_accessible :email, :password, :password_confirmation

  validates_length_of       :password, :minimum => 3, :message => "password must be at least 3 characters long", :if => :password
  validates_confirmation_of :password, :message => "should match confirmation", :if => :password
end
# controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
  before_filter :require_login
  skip_before_filter :require_login, :o nly => [:index, :new, :create]
  
  def new
    @user = User.new
  end
  
  def create
    respond_to do |format|
      if @user = login(params[:username],params[:password])
        format.html { redirect_back_or_to(:users, :notice => 'Login successful.') }
        format.xml { render :x ml => @user, :status => :created, :location => @user }
      else
        format.html { flash.now[:alert] = "Login failed."; render :action => "new" }
        format.xml { render :x ml => @user.errors, :status => :unprocessable_entity }
      end
    end
  end
    
  def destroy
    logout
    redirect_to(:users, :notice => 'Logged out!')
  end
end

# views/user_sessions/new.html.erb

Login

<%= render 'form' %> <%= link_to 'Back', user_sessions_path %>
# views/user_sessions/_form.html.erb

<%= form_tag user_sessions_path, :method => :post do %>
  
<%= label_tag :username %>
<%= text_field_tag :username %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Login" %>
<% end %>
# config/routes.rb
  root :to => 'users#index'
  resources :user_sessions
  resources :users
  
  match 'login' => 'user_sessions#new', :as => :login
  match 'logout' => 'user_sessions#destroy', :as => :logout
# views/layouts/application.html.erb


  
    
      <%= stylesheet_link_tag    "application" %>
      <%= javascript_include_tag "application" %>
      <%= csrf_meta_tags %>
  
  
    
  
  

<%= notice %>

<%= alert %>

<%= yield %>
# controllers/users_controller.rb
class UsersController < ApplicationController
  before_filter :require_login
  skip_before_filter :require_login, :except => [:destroy]
end

これでログイン可能になります。

このプラグインには他にもTwitter認証やfacebook認証もできるみたいで「external」をサブモジュールに
指定すればできるらしいです。

■参照URL
・Simple Password Authentication
https://github.com/NoamB/sorce……entication

・外部連携してログインする方法
https://github.com/NoamB/sorce……i/External

01

2012/02

勉強がてら構築してみました。以前はrailsのWebサーバはThinで構築していたのですが、
最近流行している「Unicorn」、さらにはフロントにリバースプロキシとHTTP用のサーバ「nginx」
をおいて構築してみることにします。

仕組みについてはこちらのサイトがよくまとめられていたので概要つかむによいでしょう。

まずは、nginxのインストールを行います。インストールはあらかじめrpm をインストールしてからyumでインストールし直します。

rpm -ivh nginx-release-centos-6-0.el6.ngx.noarch.rpm
yum install nginx

一度、デフォルトでnginxで起動するかどうかの確認を行います。「service nginx start」で http://hoge.moge にアクセスしてnginx用の画面が表示されていればとりあえずはインストール完了です。

以下、Unicornがnginx経由でアクセスできるようにするための設定ファイルになります。

upstream hoge.moge {
    server unix:/var/www/test/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name hoge.moge;

  root /var/www/test/public/;
  access_log log/access.log;
  error_log  log/error.log;

  location / {
    if (-f $request_filename) {
        break;
    }
    # ファイルが存在しなければunicornにproxyする
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://hoge.moge;
  }

  # この記述がないと静的ファイルが表示されなかった
  location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
    expires 1y;
  }
}

なんか書き方はPerlbalよりわかりやすいようなイメージしました。気のせいかもしれませんが。。。

次は、Unicornのインストールです。gemでパッケージをインストールします。

gem install unicorn

これでおしまい。

その後、Railsで展開されているコンフィグファイルに設定情報を記述します。

vi config/unicorn.conf
# -*- coding: utf-8 -*-
# ワーカーの数
worker_processes 2

# capistrano 用に RAILS_ROOT を指定
working_directory "/var/www/test/"

# ソケット
#listen '/tmp/unicorn_of_example.sock'
#listenFile = working_directory << 'tmp/sockets/unicorn.sock'
listen  '/var/www/test/tmp/sockets/unicorn.sock'

# ログ
log = '/var/log/rails/unicorn.log'
stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])
stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT'])


# ダウンタイムなくす
preload_app true

before_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

    old_pid = "#{ server.config[:pid] }.oldbin"
    unless old_pid == server.pid
        begin
            # SIGTTOU だと worker_processes が多いときおかしい気がする
            Process.kill :QUIT, File.read(old_pid).to_i
        rescue Errno::ENOENT, Errno::ESRCH
        end
    end
end

after_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

最後にそれぞれを起動します。

unicorn_rails -c config/unicorn.rb -E production -p 5000 -D
service nginx start

指定のURLからアクセスして画面がみれれば完成でし!

□参考URL
http://nginx.org/
http://techracho.bpsinc.jp/bps......07_28/2208

31

2012/01

rubyで新サービスを開発するためにいろいろ技術調査やら実験しているわけでして、試行錯誤しているわけなフェーズな訳です。
とはいうもののなんだかんだしてrubyのバージョンがあがってフレームワークの並に乗れなかったりするのは嫌なので、システム
からチョッち上の層でバージョン管理してくれるものあったのでインストールしてみることにします。

今回はMacからのインストールですが、以前リナックスに同じバージョン管理してくれるRVMをいれていまして
「update」するとめんどくさいという経験談を聞いてちょっと公開してしまいましたがとりあえずはこれで運用しつつ、
Macではrbenvで運用してみることにします。

でもその前に、久々にMacに入っているサーバやらソフトをbrewでアップデートします。brew入れてから半年もたってないけどもろもろ更新されてるみたいですね。

# brew update
# brew upgrade                                                                                                                                                                                                    [~/config]
==> Upgrading 9 outdated packages, with result:
cmake 2.8.7, curl 7.23.1, emacs 23.3b, git 1.7.9, icu4c 4.8.1.1, libevent 2.0.16, readline 6.2.2, mysql 5.5.19, tmux 1.6

・
・
・
・

rbenvのインストール

# brew install rbenv
# brew install ruby-build

brewは楽でいいですね。

その後に.zshrcに以下の処理を追加します。

eval "$(rbenv init -)"
source ~/.rbenv/completions/rbenv.zsh

rubyのインストール

まずはちょっと前のバージョンをいれてみることにします。

# rbenv install 1.9.2-p290
# rbenv global 1.9.2-p290
# rbenv rehash
# ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.2.0]

「rbenv rehash」でインストールしたバージョンを反映させるみたいです。これで設定は完了です。

以下も同様ですね。

# rbenv install 1.9.3-p0
# rbenv global 1.9.3-p0
# rbenv rehash
# ruby -v
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0]

こんな感じにすれば、現在インストールされているものと利用されてるものが確認できるそうですね。

# rbenv versions                                                                                                                                                                                                  [~/.rbenv]
  1.9.2-p290
* 1.9.3-p0 (set by /Users/nakajimadaichi/.rbenv/version)
31

2012/01

さくらのVPSを借りることになったので早速Ruby+Rails+Thinで構築してみることにします。

「Thin」てどういうものかって勝手にまとめてみると軽量で高速なRails専用のWebサーバらしいです。

the Mongrel parser, the root of Mongrel speed and security
Event Machine, a network I/O library with extremely high scalability, performance and stability
Rack, a minimal interface between webservers and Ruby frameworks

RVMのインストール

# bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

設定情報を追加

[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"
# rvm  install 1.9.3
# rvm  install 1.9.2
# rvm --default use 1.9.3

RubyGemsのインストール

sudo /usr/local/rvm/bin/ruby setup.rb
gem update --system

Mysqlのインストール

gem install mysql2

これの前提条件として

yum install mysql mysql-server mysql-devel 

が必要になる。

Thinのインストール:Ruby専用サーバ

gem install execjs
gem install therubyracer
gem install thin

これでブラウザで画面がみれるようになれば完成です。しかし、Thinとは別にまたUnicornらしきものがでていることを知ったので勉強がてらいれてみることにします。それは後ほど。

■リファレンス
http://www.ruby-lang.org/ja/
http://rubygems.org/
http://beginrescueend.com/
http://code.macournoyer.com/thin/