スケルトン・エピ

letsspeakのブログです。

FuelPHPのserver_gmt_offsetの設定について調べてみた

前記事でstationwagonを動かすまでの手順をかいてみたところ、@kenji_sさんから、server_gmt_offsetは0のままでも良いのではという旨のご指摘を頂いたので、実際に自分でも調べてみました。

偉大なる参照記事様
ORMのObservers、タイムゾーン設定(Asia/Tokyo)で気をつける事

ほとんど上記記事の通りなのですが、設定が微妙に違ったので、少し解説が必要と感じたポイントなども加え流れをまとめておきます。

結論

サーバ側でロケール設定を日本時間に合わせてある場合、fuel/app/config.php のserver_gmt_offsetは初期値である 0 のまま変更しなくても良い。

下記のように date コマンドで現在時刻が表示される環境なら大丈夫かと思います。

$ date
2013年  3月  9日 土曜日 13:45:30 JST

(詳しく調べてはいませんが、最終的に php の strftime() 使用時の環境設定も関係しそうな気がします。)

調査前

まずは、fuel/app/config.php

 'server_gmt_offset'  => 3600 * 9,

の状態でstationwagonのarticleを作成してみました。

f:id:letsspeak:20130309145127p:plain

201303091304に投稿したunix time が 1362834283 となっています。
こちらの変換サイトで変換すると 2013/3/09 22:04:43 となっていますね。
まさにご指摘頂いた通り9時間分ずれてしまっていることがわかります。

created_at生成までの流れを追う

Model内でのarticle生成時の挙動を確認します。

fuel/app/classes/model/article.php
  protected static $_observers = array(
    'Orm\\Observer_CreatedAt' => array('before_insert'),
    'Orm\\Observer_UpdatedAt' => array('before_save'),
  );  

$_ovserversの設定により、Modelがデータベースに書き込まれる際の before_insert という信号で 'Orm\\Observer_CreatedAt の before_insert が呼ばれるようになっているようです。

中で何をしているか見てみます。

fuel/packages/orm/classes/observer/createdat.php
public function before_insert(Model $obj)
  {
    $obj->{$this->_property} = $this->_mysql_timestamp ? \Date::time()->format('mysql') : \Date::time()->get_timestamp();
  }

$objはModel自身、今回は fuel/app/classes/model/article.php の Model_Article を指すようになる仕組みで、$this->_property は何も指定が無ければ 'created_at' という値になるようです。

つまり、ここで自動的に Model_Articleの created_at に設定する日付を生成しているということです。

何も指定が無い場合は _mysql_timestamp が false になり、Date::time()->get_timestamp() が呼ばれます。
mysql_timestamp を true に設定していた場合は、 Date::time()->format('mysql') が呼ばれます。

Date::time()ってなに?

php初心者なので最初、Date::time() が何をやっているのか分からなかったのですが、

fuel/core/classes/date.php
   public static function forge($timestamp = null, $timezone = null)
   {
     return new static($timestamp, $timezone);
   }
 
   public static function time($timezone = null)
   {
     return static::forge(null, $timezone);
   }

Date自身がメモリ上に生成されなければ get_timestamp() や format('mysql') といったクラスメソッドを呼び出す事ができないので、このくだりでDate自身を生成しているようです。

Objective-Cで書くとこんな感じですね。

return [[Date time] format:@"mysql"];

あるいはもっとわかりやすく書くと

Date *date = [[[Date alloc] init] autorelease];
return [date Format:@"mysql"];

となるかと思います。

今回、time()の引数には何も指定されていないので、$timestamp = null, $timezone = null の状態で初期化されます。
初期化時にはルール上、下記の __construct() が呼ばれるようです。

fuel/core/classes/date.php
  public function __construct($timestamp = null, $timezone = null)
   {
     ! $timestamp and $timestamp = time() + static::$server_gmt_offset;
     ! $timezone and $timezone   = \Fuel::$timezone;
 
     $this->timestamp = $timestamp;
     $this->set_timezone($timezone);
   }

はい、やっと出ました static::$server_gmt_offset;
このタイミングで time() との加算値が $timestamp に格納されます。

Dateクラス内での日付生成挙動

それでは、format('mysql')時とget_timestamp()時の挙動を見てみます。
fuel/core/classes/date.php

  public function format($pattern_key = 'local', $timezone = null)
  {
    \Config::load('date', 'date');

    $pattern = \Config::get('date.patterns.'.$pattern_key, $pattern_key);

    // determine the timezone to switch to
    $timezone === true and $timezone = static::$display_timezone;
    is_string($timezone) or $timezone = $this->timezone;

    // Temporarily change timezone when different from default
    if (\Fuel::$timezone != $timezone)
    {   
      date_default_timezone_set($timezone);
    }   

    // Create output
    $output = strftime($pattern, $this->timestamp);

    // Change timezone back to default if changed previously
    if (\Fuel::$timezone != $timezone)
    {   
      date_default_timezone_set(\Fuel::$timezone);
    }   

    return $output;
  }

   public function get_timestamp()
  {
    return $this->timestamp;
  }

get_timestamp() 呼び出し時は $timestamp をそのまま返しています。
また、format() 呼び出し時は

    $output = strftime($pattern, $this->timestamp);

のくだりで$timestampを使用しています。
引数に 'format' 指定時の $pattern は下記にありました。

fuel/core/config/date.php
     'mysql'    => '%Y-%m-%d %H:%M:%S',

phpの対話シェルで確認

それぞれの挙動をphpの対話シェルで確認します。

time()
$ php -a
Interactive shell

php > echo time();
1362810492

unix time で帰ってきますので、先ほどの変換サイトで変換します。
サーバ側でロケール設定を日本時間に合わせてある場合、現在の日本時間が返ってくると思います。

strftime()
$ php -a
Interactive shell

php > echo strftime('%Y-%m-%d %H:%M:%S', time());
2013-03-09 13:40:52

下記警告が出ましたがとりあえず現在時刻が返ってくると思います。

PHP Warning:  strftime(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'Asia/Tokyo' for 'JST/9.0/no DST' instead in php shell code on line 1

server_gmt_offsetを修正

という訳でserver_gmt_offsetの値を 0 に修正して最終確認です。

fuel/app/config.php

 'server_gmt_offset'  => 0,

f:id:letsspeak:20130309154548p:plain
201303091424に投稿したunix time が 1362806678 となっています。
こちらの変換サイトで変換すると 2013/3/09 14:24:38 となっています。
ばっちりです!

参照記事との違いとデータベース構造

ORMのObservers、タイムゾーン設定(Asia/Tokyo)で気をつける事
上記参照記事の場合はModelsのObservers設定時に

protected static $_observers = array(
  'Orm\\Observer_CreatedAt' => array(
    'events' => array('before_insert'),
    'mysql_timestamp' => true, // datetime 型で挿入させる
    'property' => 'created', // テーブルカラム名を created に変更
  ),
);

というように mysql_timestamp, property などの引数が指定されていますが、stationwagonでは

fuel/app/classes/model/article.php
  protected static $_observers = array(
    'Orm\\Observer_CreatedAt' => array('before_insert'),
    'Orm\\Observer_UpdatedAt' => array('before_save'),
  );  

となっており、引数設定が行われていません。

先ほども書きましたが、

Orm\\Observer_CreatedAtの引数に何も指定が無い場合はDate::time()->get_timestamp() が呼ばれ、mysql_timestamp を true に設定していた場合は、 Date::time()->format('mysql') が呼ばれます。

この違いが発生している理由は、
前回記事に付け足したdatabase.mysqlにありました。

database.sql

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `password` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
  `email` varchar(70) COLLATE utf8_unicode_ci DEFAULT NULL,
  `profile_fields` text COLLATE utf8_unicode_ci,
  `group` int(11) DEFAULT NULL,
  `last_login` bigint(20) DEFAULT NULL,
  `login_hash` tinytext COLLATE utf8_unicode_ci,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`),
  UNIQUE KEY `email` (`email`),
  `created_at` bigint(20) unsigned DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

他のテーブルからのコピペで created_at が bigint 型になっています。
$_observersの設定を顧みても、stationwagon としてはこのコピペは正解だったようです。

created_dtにdatatime型を使いたい場合は、
$_observersの設定で'mysql_timestamp' => true を指定する必要がありそうです。

気になった事

phpの対話シェルでstrftime()を実行した際に

PHP Warning: strftime(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'Asia/Tokyo' for 'JST/9.0/no DST' instead in php shell code on line 1

という警告が出てきました。
この調査は宿題にしますが、'mysql_timestamp' => true 時はstrftime() が使われるのでちょっと気になりますね。

初心者がCentOSでFuelPHPのstationwagonを動かしてみた

Webアプリケーションを作ろうと、さくらのVPS (CentOS 6.3) で Ruby on Rails を弄ったりしていたのですが、Railsはどうも記述されていないルールが掴めないので、もう一度FuelPHPをはじめなおしてみました。

今回も意外と詰んだりしたので手順を残しておきます。
初心者なので間違っている設定などあるかもしれません。ご注意ください。

偉大なる先人様の参照記事
FuelPHP のサンプルアプリ「Stationwagon」をみてみる - A Day in Serenity @ kenjis

0. nginx, apache, MySQL をインストール

基本設定も終了済みの状態から始めました。
色々ググって探せばなんとかなると思います。たぶん。

1.nginx と apache の連携

今回は既に複数のunicorn_railsと連携中のnginxさんにapacheの設定を追加しました。
apacheさんも既にhogeに割り当てられていたためバーチャルホストで対応します。

/etc/nginx/nginx.conf
  upstream fuelhoge {
    server 127.0.0.1:8000;
  }

  upstream hoge {
    server 127.0.0.1:8001;
  }

  server {
    listen 80;
    server_name fuelhoge.jp.;

    access_log /var/log/nginx_fuelhoge_access.log;
    error_log /var/log/nginx_fuelhoge_error.log;

    proxy_connect_timeout 60;
    proxy_read_timeout    60;
    proxy_send_timeout    60;

    location / {

      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://fuelhoge;
      proxy_redirect off;
    }
  }

  server {
    listen 80;
    server_name hoge.jp;

    proxy_connect_timeout 60;
    proxy_read_timeout    60;
    proxy_send_timeout    60;

    location / {
      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;
      proxy_redirect off;
    }
  }
/etc/httpd/conf/httpd.conf
Listen 8000
Listen 8001

<VirtualHost *:8000>
  ServerName fuelhoge.jp
  DocumentRoot /var/www/fuelhoge
</VirtualHost>

<VirtualHost *:8001>
  ServerName hoge.jp
  DocumentRoot /var/www/hoge
</VirtualHost>

<Directory "/var/www/fuelhoge/stationwagon/public">
  AllowOverride All
</Directory>

NameVirtualHost *:8001

(前回のmacでの設定時同様、AllowOverride All の設定を忘れていて少し詰みました。)

2.stationwagonのインストールとパーミッション設定

$ git clone git://github.com/abdelm/stationwagon.git
$ cd stationwagon
$ oil r install

ここでは操作ユーザーの書き込み権限が無くてgit cloneで詰みました。
作業ユーザーは既にapacheグループに追加済みでしたので、/var/www/fuelhoge/ のapacheグループの書き込み権限を有効にしました。

$ chmod 775 /var/www/fuelhoge

3.stationwagonのconfig.phpを設定

設定は参照元の記事の通りです。

--- a/fuel/app/config/config.php
+++ b/fuel/app/config/config.php
@@ -41,7 +41,7 @@ return array(
         *
         * Set this to false or remove if you using mod_rewrite.
         */
-       'index_file'  => 'index.php',
+       'index_file'  => '',
 
        'profiling'  => false,
 
@@ -71,7 +71,7 @@ return array(
         */
        'language'           => 'en', // Default language
        'language_fallback'  => 'en', // Fallback language when file isn't available for default language
-       'locale'             => 'en_US', // PHP set_locale() setting, null to not set
+       'locale'             => 'ja_JP.utf8', // PHP set_locale() setting, null to not set
 
        'encoding'  => 'UTF-8',
 
@@ -81,8 +81,8 @@ return array(
         * server_gmt_offset    in seconds the server offset from gmt timestamp when time() is used
         * default_timezone             optional, if you want to change the server's default timezone
         */
-       'server_gmt_offset'  => 0,
-       'default_timezone'   => 'UTC',
+       'server_gmt_offset'  => 3600 * 9,
+       'default_timezone'   => 'Asia/Tokyo',
 
        /**
         * Logging Threshold.  Can be set to any of the following:
@@ -94,7 +94,7 @@ return array(
         * Fuel::L_INFO
         * Fuel::L_ALL
         */
-       'log_threshold'    => Fuel::L_WARNING,
+       'log_threshold'    => Fuel::L_ALL,
        'log_path'         => APPPATH.'logs/',
        'log_date_format'  => 'Y-m-d H:i:s',
【注意】上記では server_gmt_offset を 3600*9 秒 = 9時間 に変更していますが、サーバ側でロケール設定を日本時間に合わせてある場合、変更せずに 0 のままで問題ないようです!

4.データベースの作成

データベースの作成も参照元記事と同じです。
MySQLにログインして下記コマンドを打ち込みます。

> CREATE USER 'stationwagon'@'localhost' IDENTIFIED BY '***';

> GRANT USAGE ON * . * TO 'stationwagon'@'localhost' IDENTIFIED BY '***' 
 WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 
 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;

> CREATE DATABASE IF NOT EXISTS `stationwagon` ;

> GRANT ALL PRIVILEGES ON `stationwagon` . * TO 'stationwagon'@'localhost';

テーブルの作成は面倒なので stationwagon/database.sql を流し込んだのですが、実際に動かして Sign Up を実行したときにusers テーブルに crated_at が無いというエラーが出たため、下記のように変更しました。

diff --git a/database.sql b/database.sql
index a87b3aa..88da9b8 100644
--- a/database.sql
+++ b/database.sql
@@ -11,7 +11,8 @@ CREATE TABLE `users` (
   `login_hash` tinytext COLLATE utf8_unicode_ci,
   PRIMARY KEY (`id`),
   UNIQUE KEY `username` (`username`),
-  UNIQUE KEY `email` (`email`)
+  UNIQUE KEY `email` (`email`),
+  `created_at` bigint(20) unsigned DEFAULT NULL
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

database.sqlをデータベース stationwagon へ流し込みます。

mysql -u stationwagon -p -h localhost stationwagon < database.sql

5.データベース接続設定

これも参照先の記事とまったく同じで大丈夫でした。

--- a/fuel/app/config/development/db.php
+++ b/fuel/app/config/development/db.php
@@ -7,8 +7,9 @@ return array(
        'default' => array(
                'connection'  => array(
                        'dsn'        => 'mysql:host=localhost;dbname=stationwagon',
-                       'username'   => 'root',
-                       'password'   => '',
+                       'username'   => 'stationwagon',
+                       'password'   => '***',
                ),
+               'table_prefix' => 'sw_',
        ),
 );

6.mod_rewriteの設定

1に書いた通りAllowOverride Allが問題なければ大丈夫でした。


以上です。
想像以上に詰まりましたが、参照元の記事に加えて、まさかの自分の前回の記事がとても頼りになりました。
もし間違いなどがありましたらご指摘いただけると嬉しいです!

追記

@kenji_sさんからTwitterでご指摘頂いた、server_gmt_offsetの設定について修正しました。
ご指摘ありがとうございます!

シンタックスハイライトをXcodeっぽくしてみた

カスタムCSSデザイン設定

.synComment { color:#3e9910 }
.synConstant { color:#cc0000 }
.synIdentifier { color:#454545 }
.synPreProc { color:#7f3f11 }
.synSpecial { color:#c000c0 }
.synStatement { color:#cc16ad }
.synType { color:#cc16ad }

結果

#import "CCLayer.h"
#import "SRPG.h"
#import "SRArea.h"

@interface SRAreaLayer : CCLayer

- (void)removeAllAreaSprite;
- (void)drawArea:(SRArea*)area;

@end

// on "init" you need to initialize your instance
-(id) init
{
	// always call "super" init
	// Apple recommends to re-assign "self" with the "super" return value
	if( (self=[super init])) {
        
        // create map layer
        _mapLayer = [SRMapLayer node];
        [self addChild:_mapLayer];
        
        // create area layer
        _areaLayer = [SRAreaLayer node];
        [self addChild:_areaLayer];
        
        // create units
        self.unitArray = [CCArray array];
        
        SRUnit *unit1 = [[SRUnit alloc] init];
        unit1.spriteFilename = @"pc01_00.png";
        unit1.fieldPoint = SRFieldPointMake(5, 5);
        unit1.moving = 3;
        [self.unitArray addObject:unit1];
        
        SRUnit *unit2 = [[SRUnit alloc] init];
        unit2.spriteFilename = @"pc01_00.png";
        unit2.fieldPoint = SRFieldPointMake(2, 10);
        unit2.moving = 5;
        [self.unitArray addObject:unit2];
        
        // create unit layer and set units
        _unitLayer = [SRUnitLayer node];
        [_unitLayer setUnits:_unitArray];
        [self addChild:_unitLayer];
        
        self.selectedUnit = nil;
        self.phase = SRFieldScenePhaseNoAction;

	}
	return self;
}

イデアについて

酔っぱらいながら書いているという言い訳をしつつ。

 

イデアという概念と出会ったのは高校の世界史だったのだけれども、僕の中の解釈としては、イデアは「想像における者の概念」という風に理解して、わりとすんなり受け入れることができました。

 

たとえば、バナナが現実にあったとして、バナナを見ずに(あるいは見ていてもいいのだけれども)頭の中に想像されるバナナと、現実のバナナとは違うわけです。頭のなかで自分の想像として現れる概念としての「バナナ」がイデアなのかなーという風に解釈しました。

 

時は流れ、今は一応プログラマーとして働かせて貰っていますが、最近プログラムを書くにあたって、このイデアという概念が非常に重要なのではないかと思う事が本当に多いのです。

 

ゲーム、業務用?を問わず、プログラムを書く流れとしてまず、何を満たす為のものなのかを定義して、それから、プログラムがどういう動作ならばそれが満たされるか、そしてプログラムを実際に書いていきます。

 

このプロセスの中で、僕が一番重要だと思うのが、「プログラムがどういう動作ならばそれが満たされるのか」という点で、これはまさに頭のなかに完成系のイデアを思い浮かべるタイミングとなります。

 

このイデアさえしっかり抱けていれば、後の実際にプログラムを書くプロセスは単に作業でしかなく、経験さえあれば、解決できない壁はないレベルになってしまいます。

そうなると、プログラムを書く上で一番重要なのは、イデアをより確実に抱くことなのではないかと思っています。

 

また、逆にこのイデアが抱けない場合、とりあえずのものを書いても未完成な者ができたり、後から書き直す可能性があるなーとか思いつつ書いて、やっぱり書き直すはめになった。という事が本当に頻繁に発生します。

 

プログラムを書くにあたっていは、イデアが最も重要。

これは僕の中ではほぼ確信になりつつあります。

 

また、このことはプログラム以外でも遭難じゃないかという仮説があります。

例えば、勉強会やライブなどのイベントを立ち上げる際にも、より強固なイデアを抱けた人から順にこれらの催しを実際に行動に移す事ができたり、ものをつくるだけでなく、会社などの組織をつくるにあたっても非常に重要な役割を果たしているのではないかなーと思っていたりします。

 

さて、話をプログラムに戻します。

上記の前提を経て、これからの未来の話に移ろうと思います。

 

30年もすれば、恐らく脳みそと電子機器が接続されて、脳みそで想像したものが簡単にプログラムになって出てくる未来になるのではないかと考えています。

 

僕の好きな攻殻機動隊の世界です。

 

そうなると、本当にプログラムを書く事自体はただの「作業」でしかなく、しかもそれは、ほぼ自動化されることになるでしょう。そんな時に一番重要視されるのは、まさにここまで述べてきた「イデア」の力。これだけがプログラマーに求められるものになるのではないかと感じています。

 

さらに次の話をします。

 

イデアさえあればプログラムが書ける。そんな環境になったならば、プログラム自身が自我を持ち、ターミネーターのようなプログラムが支配する世界が訪れるのではないか、そのような疑問を抱いたことがある方は少なくないと思います。

 

僕の考えでは、それはすぐには訪れないと思っています。

 

プログラムを作成するということは、少なくとも現実世界をイデアに変換する作業が根本にあって、それをコーディングするということで、コーディングの部分は自動化することは可能だと思います。

 

しかしながら、プログラム自身はイデア世界出身の存在なので、現実世界については一切知らないのです。

 

現実世界を知るためには、人間が普段感じている五感を満たしながら、同時に自身を成長させて、変化させていくことが必要になります。これは少なくとも脳みそが電子ネットワークと接続された瞬間では難しいのではないかと思います。

 

人間はイデアに指示されながら、現実世界の情報について補完する役割を果たす時期というのが少しの間続句事になるかと思います。それは、実際に機械が進化して、人間の五感の役割を果たすよりもずっと効率が良いのです。

 

その後、機械の進化とともに人間は淘汰されるのかも知れませんが、少なくとも僕が生きているうちは人間はまだ機械よりも優れた知覚機関となるのではないかなーと感じています。

 

酔っぱらった状態で15分くらいで書いてみた感じでは、そんな感じです。

 

CentOS 6.3 にRedmine をインストールしてみた

さくらのVPSを借りたものは良いけど、中々趣味プロジェクトが前に進まないので、マイルストーンを切るべくRedmine 2.1を導入してみました。

今回は既にmysqlやrbenv、Rails、nginx、git等がインストールされている環境下への導入で、nginxを通しつつホストを分ける形でのアプローチになっています。

すべてを一からインストールしようとしている方にとってはあまり参考にならないかもしれないですが、下記に手順を残しておきます。

 

なお、今回のインストールで作成/変更した設定ファイルはgistにまとめて置いておきました。どこかからのコピペばかりで、もしかすると凄まじい脆弱性が潜んでいるかもしれません。参考にされる方は自己責任でお願いします。

(あわせてツッコミなどあればよろしくお願いします。)

 

【設定ファイルのgist】

 gist:Redmine on unicorn on nginx with mysql, my configuration files. 

【環境】

 ・CentOS 6.3

 ・rbenv インストール済み

 ・Rails 3.2.8 インストール済み

 ・nginx 1.0.15 インストール済み

 ・mysql 5.1.61 インストール済み

 ・git  1.7.1 インストール済み

【参考にしたサイト等】

 rbenv+ruby-buildとunicornでもっとさくっとRedmine入れてみる

 Installing Redmine(Redmine公式Wiki)

 

1.Redmineのダウンロード 

redmineをgithubからcloneします。

$ cd /home/www/rails
$ git clone https://github.com/redmine/redmine.git
Initialized empty Git repository in /home/www/rails/redmine/.git/
remote: Counting objects: 90421, done.
remote: Compressing objects: 100% (17498/17498), done.
remote: Total 90421 (delta 71963), reused 89815 (delta 71466)
Receiving objects: 100% (90421/90421), 20.11 MiB | 1.79 MiB/s, done.
Resolving deltas: 100% (71963/71963), done.

 

2.1-stable ブランチに切り替えます。

$ cd redmine
$ git branch -a
* master
  remotes/origin/0.6-stable
  remotes/origin/0.7-stable
  remotes/origin/0.8-stable
  remotes/origin/0.9-stable
  remotes/origin/1.0-stable
  remotes/origin/1.1-stable
  remotes/origin/1.2-stable
  remotes/origin/1.3-stable
  remotes/origin/1.4-stable
  remotes/origin/2.0-stable
  remotes/origin/2.1-stable
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
$ git checkout -b 2.1-stable remotes/origin/2.1-stable
Branch 2.1-stable set up to track remote branch 2.1-stable from origin.
Switched to a new branch '2.1-stable'

$ git branch
* 2.1-stable
  master  

 

2.Redmineのインストールと起動テスト 

いつも通りbundle installを実行します。

$ bundle install --path vendor/bundle --without development test rmagick postgresql sqlite

 

mysqlredmine用のデータベースとユーザーを作成します。(passwordは独自に設定)

$ mysql -u root -p
mysql> create database redmine character set utf8;
mysql> create user 'redmine'@'localhost' identified by 'password';
mysql> grant all privileges on redmine.* to 'redmine'@'localhost';
mysql> exit

 

database.ymlをmysql用に書き換えます。

$ cp config/database.yml.example config/database.yml
$ vim config/database.yml

gist:database.yml

 

Redmineのデータベースを構築します。

$ RAILS_ENV=production rake db:migrate
$ RAILS_ENV=production rake redmine:load_default_data

Select language: ar, bg, bs, ca, cs, da, de, el, en, en-GB, es, et, eu, fa, fi, fr, gl, he, hr, hu, id, it, ja, ko, lt, lv, mk, mn, nl, no, pl, pt, pt-BR, ro, ru, sk, sl, sq, sr, sr-YU, sv, th, tr, uk, vi, zh, zh-TW [en] ja

 

webrickでの起動実験を行います。ポート3000にアクセスしてRedmineが開けば成功。

$ ruby script/rails server webrick -e production

 

3.unicornの導入と設定 

デフォルトではunicornが入っていないので、Gemfile.localを生成してインストールします。

$ echo 'gem "unicorn"' > Gemfile.local
$ bundle install

 

おもむろにunicornの設定ファイルを持ってきて起動実験します。ポート5001にアクセスしてRedmineが開けば成功。

$ vim config/unicorn.rb 
$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D -p 5001

gist:unicorn.rb

 

4.nginxの設定 

今回はnginx側でBASIC認証を行うため.htpasswdを生成します。username、passwordはそれぞれ独自に設定。

$ su
$ printf "username:$(openssl passwd -1 password)\n" >> .htpasswd

 

nginxの設定でRedmine用のホストを追加して再起動します。

$ vim /etc/nginx/nginx.conf
$ service nginx restart

gist:nginx.conf

きちんと3000番と5001番のポートを閉じてから、 redmine.charag.jpにアクセスしてRedmineが開けたら成功です!

 

まとめ 

nginxの設定にもっとも時間を取られました。

当初 hoge.jp/redmine/ で繋がるようにしたかったのですが、rewriteやproxy_passの設定が分からず、リダイレクトループが発生。なんとか解決したものの、今度はRedmine側が/redmine運用を想定されていなくて面倒な事になり、ホスト運用に切り替えました。

ホスト運用となってしまえば、アプリ自体の導入もとてつもなく簡単で、nginxもすんなり設定できました。Railsは一度導入さえしてしまえば色んなアプリの導入が楽ちんですね!!病み付きになりそうです。次回はアクセスログの統計アプリなどを入れようと思っています。

ニコニコ動画は何故日本一の動画サイトになったのか

 ニコニコ動画は何故日本一の動画サイトになったのでしょうか。当然ながらアイデア力や、開発力、資本の力、受け取り側の問題など、様々な理由が複雑に絡み合ってこその成功だとは思いますが、僕が出した結論は「感情のもっとも高い点を共有できる場を提供したこと」にあると考えています。

 

 時代はインターネットの発明まで遡ります。人々は遠くの情報をすぐに得られるツールとしてインターネットを利用し始めましたが、ほぼ同時にメールや掲示板、ホームページの文章を使っての、「人と人とのコミュニケーションツール」としても利用され始めました。人々は自身の想いを文章に書き連ねる事によって、お互いにその想いや感情を共有することを求めていたのです。

 

 当時のメールや掲示板等を通してのやり取りというのは、1週間〜数日間待って初めて返事がくるのが当然で、そうなると相手に贈るメッセージを考える時間も十分にあります。「こんな言葉を返そう」と思った事を何度も何度も練ってから「送信」ボタンを押すのです。いわば「理性を共有できる場」に近くなってしまう訳です。

 

 それに対して、ニコニコ動画では流れる動画に対してその時限りのコメントを残すので「こんな言葉を返そう」等と考えている暇などありません。今思った気持ちをすぐにコメントする必要があるのです。面白いシーンが終了して、数秒経ってから「wwwwww」等というコメントが流れてきても興ざめするだけです。

 

 

 さて、ここまで敢えて名前を出していませんでしたが、Youtubeではそうも行きません。動画の提供者に対する感情をコメントとして書いた時には、殆どの人が一度読み返してから、修正などを施して送信します。これでは理性が干渉してしまうのです。

 

 Twitterニコニコ動画にかなり近いツールです。思った事をすぐにツイートという形で発現することができるので、ニコニコ動画と同じく「感情のもっとも高い点を共有できる」と言えると思います。もし既にTwitterを利用した事があるなら、3日前のツイートを見直してみてください、改めてそのツイート読み直して、今同じ事を世の中に対して発表する必要があると感じるでしょうか。

 

 ここで必要があると感じる方は、もしかするとTwitterの「感情のもっとも高い点を共有できる」という利点を享受出来ていないのかも知れません。一般的なユーザーは「腹減った」とか「おやすみ」とか本当にどうでも良い事をつぶやいています。これらは全く理性が伴わないけれども、発動した瞬間の生の感情そのものです。これがYoutubeTwitterニコニコ動画の決定的な違いと考えています。

 

 

 次に「場の提供」という側面を見てみます。先ほど書いた通りTwitterでも感情のもっとも高い点を共有することは可能ですが、場という側面があまりにも広すぎると考えています。(最近は場を制限するハッシュタグという機能もかなり使われていますが...。)インターネットの発明当初も 各所でチャットというリアルタイムに近いコミュニケーションツールが存在しましたが、これも同様です。ニコニコ動画では、特定の「動画」という共通のお題を用意することで、「同じ場」の中でその時に感じた想いを共有する事ができるツールなのです。

 

 2chにおける実況でもニコニコ動画とほぼ同じ体験を味わうことができますし、ニコニコ動画よりも2chの実況の方が歴史も古いのですが、「多くの人が容易に体験できる場」と考えれば2chはその候補から外れてしまうのはお分かり頂けると思います。(僕も個人的にはニコ生よりはなん実の方が好きでした。)

 

 

 さて最後になりますが、受け取り側の問題にも言及したいと思います。ニコニコ動画のユーザー層は10代〜20代と言われていますが、日本の不景気の影響をもろに受けてる層と言えます。不景気で仕事がなくて、人生の余裕も無く、人と人同士のリアルコミュニケーションが失われつつあります。

 

 そんな中、掲示板等よりももっと高い、リアルタイムに近い、熱い感情を共有できて、ユーザーごとに自分の時間のなかで楽しめる場を用意したのがニコニコ動画でした。逆にこれが流行らない理由があれば、是非教えて欲しい所です。

 

 

 以上が僕が考える理由です。

動画サイトでニコニコ動画を超える感情共有をする為には、ビデオチャット以外に思いつかないほど、ニコニコ動画は突き抜けているのではないかと思っていますが、最近はポータルサイト化するなど、逆走している気配も感じるところであります。ニコニコ動画さんには今後も日本のウェブ業界の先頭を走っていって欲しいですね!!