Edit
Install Ruby

yum からのインストールだと現在、ver 1.8.7 がインストールされる。最新の安定番を付きたい場合、ソースからのみ。

# yum install ruby rubygems

Edit
libyamlのインストール

Rubyをインストールするにあたり、JSONに似たYAMLというのを利用するため、libyaml を導入する必要がある。

Edit
ソースコードから

# wget http://pyyaml.org/download/libyaml/yaml-0.1.6.tar.gz
# tar zxvf yaml-0.1.6.tar.gz
# cd yaml-0.1.6
# ./configure
# make
# make install

Edit
yumリポジトリーから

libyaml は、通常のCentOSなどの通常のディストリビューションの yum には含まれないため、yum のリポジトリに、libyaml を含む リポジトリーを yum に登録する必要がある。その後、libyaml-devel をインストールする。

# rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
# yum install libyaml-devel

※このURLは、このページに含まれている、PackagesのリンクURLを利用する。

Edit
その他必要ライブラリのインストール

Rubyをコンパイルするためのライブラリを一式インストール。

# yum groupinstall "Development Tools"
# yum install openssl-devel readline-devel zlib-devel curl-devel
# yum install ImageMagick ImageMagick-devel ipa-pgothic-fonts             <- option

Edit
本体のインストール。

Rubyの公式サイトはこちら。ここからソースをダウンロードしてコンパイルする。また、Ver1.9 移行は gem の同梱されるようになったので、本体をコンパイル&インストールすると一緒に gem もインストールされる。

# wget http://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.1.tar.gz
# tar zxvf ruby-2.4.1.tar.gz
# cd ruby-2.4.1
# ./configure --with-openssl-dir=/usr/local/ssl --enable-shared --disable-install-doc
# make
# make install
configure オプション概要
--with-openssl-dir=/usr/local/sslインストールされている、OpenSSLのフォルダ位置を指定
--enable-sharedsharedモードで作成。基本はこのオプションを付けておいたほうが良い
--disable-install-capiC APIのドキュメントをインストールしない。推奨
--disable-install-rdocrdoc indexesのドキュメントをインストールしない。推奨

出来上がった、 ruby がどのような、configure オプションで作られたかを確認したい場合。

# ruby -r rbconfig -e 'puts RbConfig::CONFIG["configure_args"]'

Edit
Ruby on rails(RoR)

Ruby on railsとは、rubyを利用したWEB開発フレームワークであり、WEBアプリの開発の効率を高めるものです。

Edit
install

# gem update --system
# gem install rails

Edit
URLへのアクセスから表示までの基本の流れ

  1. ユーザーがURLにアクセス
  2. ルーティングが仕分け
  3. コントローラーで値を入れる
  4. ビューがコントローラーから渡された値を表示

Edit
ルーティング仕分け

railsでは、railsのURLに来たものを、config/routes.rb が拾い上げ、仕分けを行いますが、基本は以下の様な仕組みとなっている。詳しくはここ

# vi config/routes.rb
get "users/show/:username" => "users#show"

これは、http://host/users/show/xxxx というURLが来たら、username という変数に xxxx を代入して、usersコントローラの showという関数に渡すということです。コントローラ側のプログラムでは、params[:username] という形でこのURLの変数を受け取ることが出来る。

Edit
コントローラで値を設定

# vi app/controllers/users_controller.rb
   @user = Hash.new
   @user[:username] = params[:username]

ここで定義された @user 変数は、app/views/users/show.html.erb の中で利用できるようになるが、@params は変数スコープの関係でコントローラ内でのみしか利用できないため、上記の様に一度、別の変数に設定する必要がある。

Edit
ビューがコントローラーから渡された値を表示

app/controllers/users_controller.rb で設定された値は、ビュー画面においてHTMLに置き換えることで画面にその内容を表示する。

# vi app/views/users/show.html.erb
  <p><%= @user[:username] %></p>

この「<%=」から、「%>」の範囲が、Rubyの変数が参照できる範囲であるという記号であり、最後の拡張子は Embed RuBy の略であり、この拡張子のものは、内部のこの範囲のものをHTMLに動的に展開してからHTMLファイルとして表示する仕組みとなる。
※このerbは、HTMLとしてコメントしてもRuby自体は展開されてしまうため、<%- if false -%> .....コメントしたい行.....<%- end -%> という形で、囲ってしまうのが良い

Edit
コントローラ内でデータベースにアクセスするための初期設定とアクセスの流れ

WEBアプリでは、データの保存には基本データベースを利用する。そのためRailsではデータベースを簡単にアクセスするための仕組みが準備されている。

Edit
データベースを作成する(モデルを作成する)

Railsでは、データベースとの接続には、config/database.yml によって、データベースとの接続方法を定義することで、コントローラ(実際のアプリプログラム)内で簡単にデータベースの操作を行うことができ、データの項目の作成や追加などもデータベースを操作する感覚ではなく、プログラム内のテーブルを操作するような簡単な手続きで記述できる。

# rails g model user name:string username:string address:string

このコマンドは、g = genarate(作成) user = (ユーザーというテーブル) name:string, username:string, address:string (テーブル内の各項目の設定)という意味であり、これによってDBのテーブルを作成する指示を行う。
※コントローラは、users という複数形であったなら、テーブルは1つのデータの単位になるため、テーブル名は user という単数形にすること

また項目を間違えた場合などは、

# rails d model user

という形で、一度 destory して、設定を破棄してから再度 generate すると良い。

Edit
データベースのマイグレート(準備)

上記でデータベースのレイアウトを、db/migrate/20140312110338_create_users.rb のファイル(数字の部分は上記コマンドを実行した日付時間)に、データベースの構造が作成される。その後、この情報を反映させるために、下記のコマンドを実行する。

# rake db:migrate RAILS_ENV=production

ちなみに、このコマンドは何度実行しても問題ない。

Edit
データベースに初期データを入れる。

作成されたテーブルに初期データを入れる方法は、db/seeds.rb に設定する。

# vi db/seeds.rb
  @user = User.new
  @user.name = 'John'
  @user.username = 'Jonny'
  @user.address = 'Kanagawa, Japan'
  @user.save

  @user = User.new
  @user.name = 'Micheal'
  @user.username = 'Mike'
  @user.address = 'Tokyo, Japan'
  @user.save

上記のように、1つのレコード毎に作成、設定、保存と行うことでデータベースに初期値を設定できる。

# rake db:seed RAILS_ENV=production

このコマンドが実際の初期値データをデータベースに書き込む実行コマンドとなる。
※実際のデータベース内におけるテーブル名は、複数形になるため上記であれば、users というテーブル名になる。

Edit
コントローラでデータベースにアクセスする。

<検索:文字列>

# vi app/controllers/users_controller.rb
@user = User.find_by(:username => 'search_name')       <- これはテーブルのusernameという項目で、search_name という名前のレコードを取得する関数。

<検索:ID>

@user = User.find(xxx)          <- xxxは数字

※もし検索し0件だった場合には、nil が入るので注意。特に表示上の都合で @user をそのまま利用したい場合には、Hash.new でモデルデータを作り直す必要がある。

Edit
入力画面からコントローラに情報を渡す場合。

Edit
入力画面の記述

# vi app/views/userinfos.html.erb
   <%= form_for Userinfo.new do |f| %>
       <%= f.label :title %>
       <%= f.text_field :title %>
       <%= f.label :content %>
       <%= f.text_area :content %>
       <%= f.submit %>
   <% end %>

Edit
ルーティングの設定

ルーティングファイルに、入力画面のデータをコントローラに渡す旨を記述する。

# vi config/routes.rb
   post "userinfos" => "userinfos#create"

Edit
コントローラの記述

# rails g controller userinfos index show

これは、users という機能に、index と show 関数を追加する旨を記述している。

<コントローラーで before_filter時に引数を渡す方法。>

before_filter :only => [:edit, :update, :destroy] do |c|
  c.NewFilterFunction( params[:id] )
end 

def NewFilterFunction (id)
  project = Project.find(id)
  redirect_to signin_path unless project.hidden
end

Edit
Ruby on Railsのインストール

# gem install rails

これだけ。
ちなみに、gem に登録されている機能のリストは、以下のコマンド。

# gem list --remote

Edit
サンプル作成と簡易テスト

インストールの確認をするには、サンプルの作成と表示が手頃である。

# rails new test-rails               <- サンプルの作成
# cd test-rails
# rails s                                   <- 作成したものを rails の簡易サーバで起動

その後、WEBプラウザーで表示の確認(ポートの3000番を開けておくこと)

http://localhost:3000/

Edit
環境設定

# export RAILS_ENV=production

Edit
RoRのコマンド

バージョンの確認

# rails --version

railsのプロジェクトを自身のサーバ機能で起動。(ポートは 3000)

# rails s

Edit
nginxなどのWEBサーバーとの連携

WEBサーバーとの連携にはRuby on Railsで構築されたものなど、RubyのウェブアプリケーションのソフトウェアデプロイメントができるWEBサーバーモジュールが必要となる。

Edit
Thin

Ruby用のwebserver、nginxをプロキシーとしてrailsなどのアプリを利用した場合などに利用する。公式ページはここ

Edit
プロジェクトのGemfile更新

# vi Gemfile
  gem 'thin'
  gem 'execjs'
  gem 'therubyracer'

Edit
インストール

# gem install thin

Edit
設定

<socketでの接続> nginxの設定ファイルに以下の行を追加。(php-fpmなどと同じ)

 server {
     location /redmine {
         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_set_header X-Forwarded-Proto $scheme;
         proxy_redirect off;
         proxy_read_timeout 300;
         proxy_pass http://redmine;
     }
     location ~ .*\.(jpg|JPG|gif|GIF|png|PNG|swf|SWF|css|CSS|js|JS|inc|INC|ico|ICO)$ {
         root    /var/www/htdocs/redmine/public;
         index   index.html;
         expires 30d;
         break;
     }
 }
 upstream redmine {
    server unix:/usr/local/nginx/tmp/thin.0.sock;
    server unix:/usr/local/nginx/tmp/thin.1.sock;
    server unix:/usr/local/nginx/tmp/thin.2.sock;
    server unix:/usr/local/nginx/tmp/thin.3.sock;
 }

※上記の例では、起動するサーバーの数は4つ。

<ポートでの接続>

   proxy_set_header Host $host;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Host $http_host;
   proxy_set_header X-Forwarded-Server $host;
   proxy_set_header X-Real-IP $remote_addr;

   location /remote {
      proxy_pass       http://proxy.mydomain.com:3000;
      proxy_redirect   default;
   }

※proxy項目は locationの中でも問題ない。

Edit
実行

<起動>※なぜかbundle exec を先頭につけないと起動しない。

#  bundle exec thin start -e production -s 4 -S /usr/local/enginx/tmp/thin.sock
オプション概要
-eproduction(初期値=development)RAILS_ENVの設定を行う
-s4起動するサーバーの数
-S/usr/local/enginx/tmp/thin.sockソケット接続する場合のsockファイルの位置
-p3000ポート接続の場合のポート番号
-a(初期値=0.0.0.0)バインドするIPアドレス
--sslSSL通信を有効化

サーバー数を指定した場合、サーバの数に応じてsockファイルが作成されるため、nginx.conf で指定するソケットファイル名に注意が必要。

(例:-s 2 で2つthinサーバを起動した場合、指定した場合ソケット名を「thin.sock」と指定しても、nginxからは、thin.0.sock thin.1.sock などとファイル名の中に、数字が追加されたファイル名になる)

※socketで、Thinを起動した場合は「Thin起動後」webサーバー側も再起動が必要

<停止>

#  thin stop -e production -s 4 -S /usr/local/nginx/tmp/thin.sock

※起動時と同じ引数である必要がある。

Edit
運用

テストなどでは上記のコマンドラインからの実行でもよいが、サーバーでの正式動作の際には自動的に起動するようにする。

<myapp.ymlの作成>

# cd <railsプロジェクトフォルダ>
# thin config -C myapp.yml -e production -s 4 -S /usr/local/nginx/tmp/thin.sock

<myapp.ymlの例>

---
chdir: "/var/www/site/collavier.com/redmine-2.4.3"
prefix: /redmine                                                          <- http://domain/redmine などサブディレクトリにする場合
environment: production
user: redmine
timeout: 30
log: log/thin.log
pid: tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
servers: 4
socket: "/usr/local/nginx/tmp/thin.sock"                   <- socketの場合、portの場合は port: 3000 などに。
daemonize: true

<テスト動作>

# bundle exec thin start -C myapp.yml

<サービス登録>

Edit
Unicorn

thinと較べてデプロイ時間が短くなる。

Edit
インストール

# gem install unicorn

Edit
Gemfileの修正

GemfileにUnicornを利用する旨設定

# vi Gemfile
  gem 'unicorn'

Edit
設定ファイル

詳しくはこのページがわかりやすい。

# vi config/unicorn.conf.rb
  working_directory "/var/www/html/redmine"
  worker_processes 4
  timeout 75
  listen 3000, :backlog => 2048   # default 8080
  #listen "tmp/run/unicorn.sock", :backlog => 64
  pid "tmp/pids/unicorn.pid"
  stderr_path "log/unicorn_err.log"
  stdout_path "log/unicorn.log"

  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
        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

<サブフォルダで起動する場合、config.ru も修正>

# vi config.ru
if ENV['RAILS_RELATIVE_URL_ROOT']
  map ENV['RAILS_RELATIVE_URL_ROOT'] do
    run RedmineApp::Application
  end
else
  run RedmineApp::Application
end

Edit
起動

# bundle exec unicorn_rails -c config/unicorn.conf.rb -E production -D --path /redmine

Edit
再リロード

# kill -USR2 (masterのpid)

Edit
Phusion Passenger

Passengerは、WEBサーバーのモジュール方式で、提供されるため nginx のように モジュールを別プロセスにして、リクエストのレスポンス遅延を回避するような特徴を持つWEBサーバーの場合、膨大な同時アクセスでトラブルが発生する可能がある。

Edit
インストール

# gem install passenger

このあと、利用するWEBサーバーに合わせたモジュールをインストールする。

Edit
nginxサーバー用モジュールのインストール

# passenger-install-nginx-module

設定ファイルへの追加

http {
     passenger_root /usr/local/lib/ruby/gems/2.1.0/gems/passenger-4.0.33;
     passenger_ruby /usr/local/bin/ruby;
}
server {
     passenger_enabled on;
     passenger_base_uri /mydocs;
}

※この部分は上記インストラーがインストール終了時に通知する。

Edit
apacheサーバー用モジュールのインストール

# passenger-install-apache2-module

Edit
passengerの導入確認

ステータス

# passenger-status

メモリ利用状況

# passenger-memory-stats

Edit
文法について

Rubyすべての文法についての説明はRubyのリファレンスページw参照。ここでは特徴的なポイントだけを説明する。

Edit
if文(if 修飾子)

Rubyでは、後置if文という表現がある。

return if flag

これは、

if flag then return end

と機能としては同じ。もしflagがtrueなら、return するという英語の表現のような文法。そのため、C言語でよく使われる else if を使ったifのネスト表現ができない。そのため、Rubyでは、elsif という else if と同じ機能を果たす専用の識別子を準備している。

Edit
イテレータ

Rubyにおいて、イテレータは他の言語の様に特別に準備された構文ではなく、Rubyの言語体系にスムーズに組み込まれている。Javaなどの他の言語ではイテレータは特別なオブジェクトの型になっており、その抽象化されたオブジェクト変数を基本に構文が考えられているが(foreachなどは典型例)、Rubyではオブジェクト自体が繰り返しを意味するメソッドを準備し、それをブロック文(クロージャーと言う言語もある)へ渡すという仕組みとなっている。

3.times {|c| print "res=" + c.to_s + "\n" }

これは3回、大括弧のブロック文を実行する。その際に繰り返しの数字を、| で囲っているcに代入して繰り返す。という内容になる。これは

name = [ "aaa", "bbb", "ccc" ]
name.each {|c| print "res=" + c.to_s + "\n" }

このように、文字列の配列を繰り返す事も可能となる。実際1行に書くと分かりづらいが下記のように改行し説明すると理解し易い。

name.each{ |引数|
   print "res=" + 引数.to_s + "\n"
}

ちなみに、同様の事を do ~ end で記述すると。

name.each do |c| print "res=" + c.to_s + "\n" end

ようするに、多くのブロック文やクロージャーに触れて出てくるように、ブロック文は無名関数として定義され、その引数にオブジェクト自体が繰り返しメソッド(timesやeachなど)にしたがって、複数回呼び出しを行っているという仕組みになる。また単純配列だけでなく

def name
  yield 10,100
  yield "look"
end
name { |c| print "res=" + c.to_s + "\n" }

結果

res=10
res=look

と表現することもできる。ここでわかることは、yield 句を持つオブジェクトは、each や times などの繰り返しメソッドを必要とせず、そのままブロックに渡すことで、yield句のすべての値が終わるまで繰り返しブロック文が呼び出される。またyield句の1行目のように、2つの引数を渡すようになっていても、実行時にエラーはでない。また、

name { |c, d| print "res=" + c.to_s + ":" + d.to_s + "\n" }

結果

res=10:100
res=look

このように、第2引数を取得するようにすると、2つ目の値(ここでは yield 10,100 なので 100 の値)が取得され、存在しない yield 句のデータでは、nil が返される。

Edit
ブロック文の注意

{ ... } の方が do ... end ブロックよりも強く前に結合するため、do を使うとブロックが切り離される。

foobar a, b do .. endfoobarの引数はa, bの値とブロック
foobar a, b { .. }ブロックはメソッドbの引数、aの値とbの返り値とがfoobarの引数

Edit
他のイテレーションメソッド

str.each_byte文字列の一文字ずつ順に渡す
str.each_line文字列の一行ずつ順に渡す
1.upto(5)1, 2, 3, 4, 5 を順に渡す
5.downto(1)5, 4, 3, 2, 1 を順に渡す
1.step(10, 2)1, 3, 5, 7, 9 を順に渡す

Edit
文字列操作

基本はJavaScript等と同じだが、記述によって速度が違う。ここ また、JavaScript等と違い数字を自動的に文字に変換してくれないため、

a = "text" + 3

はエラーになる。よって明示的に

a = "text" + 3.to_s

という形で、数字を文字に変換する to_s メソッドを利用する。逆の場合は

a = "1000".to_i

となる。

Edit
トラブルシューティング

Edit
同じフォルダにあるファイルを require で読み込もうとすると、cannot load such fileでエラーになる。

ruby 1.9 移行、他の linux コマンドのように、require './readfile.rb' のように、「./」をつける必要がある。

Edit
Page not foundが表示される。

下記のようなページが表示され、railsの画面がでない場合。

Page not found
The page you were trying to access doesn't exist or has been removed.
Back

主な理由

  1. WEBサーバーと、rails用のWEBサーバーとの接続が失敗している。
    1. 例1)port が違う。nginx.conf の proxy_pass のサーバー+ポートの部分と、thinサーバーの myapp.yml の port の値が違う。
    2. 例2)socket のフォルダ位置が違う。上記の場所のsocket 指定の部分のフォルダが同じになっていない。

Edit
DBをmigrateしようとしたら「SQLite3::SQLException: table "xxxx" already exists」がでた。

とりあえずデータベースを削除する。

# sqlite3 db/development.sqlite3
sqlite> .tables                                           <- テーブル一覧の表示
sqlite> drop table Table_Name;                <- Table_Name テーブルの削除
sqlite> .exit
# rails d model Table_Name

このあと、再度、generate する。

Edit
parseでエラー。

config/database.yml や、configuration.yml に TAB がある。

Edit
Gemの install などで証明書エラーがでる。

certificate verify failed (https://api.rubygems.org/specs.4.8.gz)

gemが参照している証明書が古いために発生する。基本的に OpenSSL と、Ruby を最新版に更新することで、解消する。確認には下記 system update を行ってみると良い。

# gem update --system

またアップデート後に bundler の再インストールも忘れないこと

# gem install bundler

参考:rubygem.orgのSSL証明書の内容を確認する。

# openssl s_client -connect rubygems.org:443 -showcerts -status < /dev/null