massの日記

日々の薪

Rails3.1.0を試してみた

ようやくRails3.1.0を試してみた。

環境

$ ruby-v
$ ruby 1.9.2p290 
$ gem --version
$ 1.8.10
$ bundle -v 
$ Bundler version 1.0.18

今回の試みとしてRailsはbundleで管理。つまりは、アプリケーション内で扱うgemとして入れてみた。

$ mkdir music_box
$ cd music_box
$ emacs Gemfile

この時点でGemfileはrailsしか書いていない。

#Gemfileの中身
source 'http://rubygems.org'
gem 'rails', '3.1.0'

Railsをbundleでインストールして、自分自身のディレクトリパスを指定してrails newする。rspecを使うため、-Tのオプションをつけた。
後は、rspecのインストールを行ってからscaffoldコマンドを使用。最後にrake db:migrateを叩いた。

$ bundle install --path ./vendor/bundle
$ bundle exec rails new ../music_box -T
$ bundle install
$ bundle exec rails generate rspec:install
$ bundle exec rails generate scaffold Music title:string path:text image:text content_type:integer
$ bundle exec rake db:migrate
$ bundle exec rails s

ここまでは大分駆け足だけれどRailsGuide Getting Startedの内容にそった形での動き。次からが大きな変更点となり、まだ学習中の場所。

app/	Contains the controllers, models, views and assets for your application. You’ll focus on this folder for the remainder of this guide.

Rails2系では見慣れなかったassetsという単語。ざっくりいうとJavaScriptcssを指しているらしい。要確認中。今まではpublicディレクトリ以下にあったjavascriptcssをここにいれる、ではpublic以下に入らない?と気になったところ、しっかり説明されていた。

public/	The only folder seen to the world as-is. Contains the static files and compiled assets.

つまりは外部から参照できるのはここのみ、静的なファイルと圧縮されたjavascriptcssがここに入れられるということ。開発時は複数のファイルに分割しておいて、アプリケーション稼働時には1ファイルにまとめるといったことができるのかな?
いくつか知っているようで知らない単語があったので、後日調べようと思ったのがscssとcoffescript、前者はコンパイルしてcssを作成するもので、後者はコンパイルしてjavascriptを作成するもの。coffescriptは勉強会に参加したこともあり、具体的にイメージできたけれど、前者はまだ未知の領域。

内部の処理も相当変わっているのだけれど、フレームワーク的、というかWebアプリケーションという意味でcompileが内包されたのは大きな見所だと思うので、今回は外からjsとcssを入れてみることにした。内部で新しく書くものはscssとcoffescriptで書くにしても、既存の外部ライブラリはどうやって使うの?と単純に疑問に思ったのが理由。
入れたのはjQueryMobile。Officialからjsとcssを取ってきて、下記のように配置。

$ mv ~/jquery.mobile-1.0b3.min.css vendor/assets/stylesheets

cssはvendor内にあるassetsに入れた。lib内にもassetsフォルダがあったのだけれど、stylesheetsのディレクトリがデフォルトであったのはvendor/assets内だったのでこちらに入れるのかと考えた。しかしjavascriptを入れる場所が見当たらない。そういえば、jquery-railsというgemでjqueryが入っているのでひとくくりで扱いたいと考えた結果、gemのreadmeでも見てみようと思い立ち、結果として下記の場所にいれた。

$ mv ~/jquery.mobile-1.0b3.min.js vendor/bundle/ruby/1.9.1/gems/jquery-rails-1.0.14/vendor/assets/javascripts/jquery.mobile-1.0b3.min.js

多分、本来はここではない。そもそも、mobileとpcのjqueryをひとくくりにしてはダメなんだけど、今回はテスト用PJということでここに置いておく。そして配置したjsやcssが自動でとりこまれるわけではなくapp/assets/javascripts/application.jsとapp/assets/stylesheets/application.cssに記入を追加して初めて取り込まれる。

#application.jsに下記を追記。
//= require jquery.mobile-1.0b3.min
#application.cssに下記を追記。
 *= require_tree ../../../vendor/assets/stylesheets/

これで外部からのjsやcssを取り込めた。
そして今回jQueryMobileを使ってみたので、どうせなら実機でみてみたいと考えてHerokuにdeployしてみることにした。

Herokuのデプロイ×Rails3.1は初。他サイトを参考にした結果として、流れは下記のような感じ。

#GemfileにHeroku環境用のgemを追記
group :production do
  # gems specifically for Heroku go here
  gem "pg"
  gem 'therubyracer-heroku'
end

Gemfileに追記すると同時にbundle install --without produtionを実行しておく。Gemfileに追記しただけだと、Gmefile.lockには何も変化がなくbundle installがまだ行われていないという形になる。ただし、production用環境にのみ必要なgemなのでlocalに入れたくない、ということで、--without productionをつけている。こうするとGemfile.lockは更新されるが、ローカル環境にはgemは入らない。

そして、一つ見落としていたのが下記の作法。

$ RAILS_ENV=production bundle exec rake assets:precompile
$ git add public/assets

assets内のものをproduction環境用にコンパイルしないといけない。
後はいつも通りにHerokuにpush,db:migrateすれば完了。

$ heroku create music_box
$ git push heroku master
$ heroku rake db:migrate

で、できたのはこんな感じ。PCのデザインは未着手。だってjQueryMobileが試したかっただけだから。内容としてはいつもyoutubeで探している動画?というか音楽をstackしていくだけのもの。作った当初はyoutube=音楽きく場所だったけれど、考えてみればvideoだと思ったので名前が微妙になったのは蛇足。

HttpStreamingなどレスポンスの返し方なども大きく改善されているらしいので、そちらも後日触れてみたい。

CoffeeScriptの勉強会に参加した

以前から興味をもっていたサーバ側JavaScript、node.jsを利用したCoffeeScript。
万葉様にて開催されていた勉強会に参加してきた。

  • CoffeeScriptって?

node.jsを利用したjsを出力してくれるもの。
jsよりも記述が少なくてすみ、RubyPythonを使っている人になじみのある記法が多い。

  • CoffeeScriptを使うための環境構築

node.jsのインストール
npmのインストール
CoffeeScriptのインストール

  • node.jsのインストール

Officialのサイトでtar.gzのダウンロードかgitプロジェクトのcloneを行う。
stable(0.4.10)とunstable(0.5.3)の切り替えをローカルで行えるようにするため、gitプロジェクトのcloneを行った。

$ mkdir git
$ cd git
$ git clone https://github.com/joyent/node.git
$ cd node
$ git tag -l
$ git checkout v0.4.10

今回使うのはstableである0.4.10。
実のところ0.5.3で最初にやったら、既知バグを踏んでしまい、nodeの起動はできたけれどCoffeeScriptの部分で詰んでしまった。

インストールはReadme.mdに記載されているので、それに従って行う。

$ ./configure
$ make
$ sudo make install
$ node -v
$ #> v0.4.10と出力されればインストール完了
  • npmのインストール

Officialのサイトに記載されているインストール手順に従う。
ただ、install.shをそのまま叩くとどんなことしているかわからなかったので、最初はcurlで取得して中身を見てから、インストール。

$ curl http://npmjs.org/install.sh
$ curl http://npmjs.org/install.sh|sh
$ npm -v
$ #>1.0.22が出力されればインストール完了

install.shを実行するだけで完了となるのは、powと同様。
これ、今風なのかなと個人的に感じた。インストールというおそらくは大多数の人が同じ作業をするだろう部分をまとめることで、設定に使うコストを下げるという考えなのかな。
なにはともあれ、これでnode.jsとnpmのインストールが完了。
いよいよCoffeeScriptのインストール。

  • CoffeeScriptのインストール

Officialのサイトの記載にされているインストール手順に従う。ここにも記載されているがインストール時に気をつけるのは使うユーザ。自分しか使わないなら、-gオプションはつけずに、マシン環境で使うなら-gをつける。-gをつける場合は、sudo権限で実行しないといけない。

$ npm install coffee-script
$ coffee -v
$ #>CoffeeScript version 1.1.2と出力されればインストール完了
  • Let syakyo

CoffeeScriptの実行環境が整ったので、OfficialのTopを写経する。

$ mkdir coffee
$ cd coffee
$ mkdir lib
$ mkdir src
$ cd src
$ emacs syakyou.coffee
$ syakyou.coffeeの中身を一部抜粋
>number = 42
>opposite = true
>number = -42 if opposite
>square = (x) -> x * x
>list = [1,2,3,4,5]
$ coffee -o ../lib/ -c ../src/
$ more ../lib/syakyou.js
>(function() {
>  var list, number, opposite, square;
>  number = 42;
>  opposite = true;
>  if (opposite) {
>    number = -42;
>  }
>  square = function(x) {
>    return x * x;
>  };
>  list = [1, 2, 3, 4, 5];
>}).call(this);

勉強会ではRails3.1にも触れていた。
Twitterで#coffeerbのタイムラインをみると当日の様子が結構よくわかるけれど、個人的にはMasherで見た方が楽しい。

Rails2.3.8へのBundler導入

Rails2.3.8のPjにBundlerを導入してみた。

まずは既存の環境にbundlerをインストール。

$ sudo gem instal bundler

Railsプロジェクトに移動

$ cd #{RAILS_ROOT}

Gemfileの作成(内容省略、確実なのはgem listで表示されたものを入れること。今使っているものをそのまま使えば、少なくともgemのversionによる依存関係の問題は発生しない)

$ emacs Gemfile

ここからはBundlerのOfficialサイトにあった、Rails2.3系のプロジェクトのBundlerの導入方法に従った。
http://gembundler.com/rails23.html
gemのパスをbundlerものに認識するようboot.rbに下記のコードを追記。

class Rails::Boot
  def run
    load_initializer

    Rails::Initializer.class_eval do
      def load_gems
        @bundler_loaded ||= Bundler.require :default, Rails.env
      end
    end

    Rails::Initializer.run(:set_load_path)
  end
end

bundlerがインストールされているか、Versionが古すぎないかをチェックするため、config/preinitializer.rbを追加

begin
  require "rubygems"
  require "bundler"
rescue LoadError
  raise "Could not load the bundler gem. Install it with `gem install bundler`."
end

if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24")
  raise RuntimeError, "Your bundler version is too old for Rails 2.3." +
   "Run `gem install bundler` to upgrade."
end

begin
  # Set up load paths for all bundled gems
  ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
  Bundler.setup
rescue Bundler::GemNotFound
  raise RuntimeError, "Bundler couldn't find some gems." +
    "Did you run `bundle install`?"
end

サーバ側とRails側の準備ができたので、gemをインストール、

$ bundle install --path ./vendor/bundle
# サーバ起動
$ bundle exec rails script/server -d

とここまでは順調に進めていたのだけどいのだけど、Production環境でエラーが発生。原因はmysqlのgem。
どうもmysqlはbundlerを想定していない作りらしく、そのままbuildするとmysqlのクライアントライブラリとかをソース内に記載されている相対パスで見てしまうらしい。
なので、gemをインストールする前にbuildパスを設定する必要がある。また、もう一つの注意点として環境によっては対象マシンが64bitだと明記する必要がある模様。

$ bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config
$ # envでARCHFLAGSが設定されているか確認。設定されていたら下記の上一行は不要。
$ export ARCHFLAGS="-arch x86_64"
$ bundle install --path ./vendor/bundle

GitでのHTTP通信覚え書き書き込み編

HTTP経由でのGitの通信を設定する上で色々とはまったので、覚え書き。
今回は書き取り編。読み取りに関してはほとんどはまりがなかったけれど、備忘録的につけておく。

目標
HTTP経由で、既存のGitプロジェクトのリポジトリをcloneし 変更を加えpushできるようにする。cloneまでは前回の読み取り編でできているので、今回は書き込みの設定。

例)HTTPサーバ=Apache、起動ユーザ=daemonの場合、リポジトリのパスは適時自分のものを設定

  • サーバ側の設定

HTTP経由の書き込みではWebDavを使う。まず初めにこちらの設定を行う。

#dav_module,dav_fs_moduleがロードされていることを確認
$ /usr/local/apache2/bin/httpd -M

davモジュールがロードされていることを確認したら、次はhttp.confにWebDavの設定を追記。


  DAV on
  AuthType Basic
  AuthName "Git"
  AuthUserFile /your/passwdfile.git #適時自分のパスワードファイルを
  Require valid-user

passwdファイルの作成

$ htpasswd -c /your/passwdfile.git

Apacheの再起動

  • クライアント側の設定

.netrcファイルの作成

$ cd
$ emacs .netrc
#machine 
#login 
#password 

gitプロジェクトのclone

$ mkdir git
$ cd git
$ git clone http://gitserver/project.git
$ cd project

gitプロジェクトへのpush

$ touch test.txt
$ git add .
$ git commit -m 'http-push test'
$ git log
$ git push origin master

ここで1つ目のはまり。

$ fatal: git-push is not available for http/https repository when not compiled with USE_CURL_MULTI.

今回クライアント側ではyumでインストールしたgitを使っていた。特にoption指定していなかったので、HTTPサポートのために使われているcurlはもともと入っていたcurlになっている。どうやらこのcurlのバージョンが古いため、git http-pushが使えないようだ。
自分で最新版のcurlをいれて、そちらをコンパイルしてみることにする。

$ yum remove git
$ cd
$ mkdir download
$ cd download
$ wget http://curl.haxx.se/download/curl-7.21.7.tar.gz
$ tar zxf curl-7.21.7.tar.gz
$ cd curl-7.21.7
$ ./configure
$ make
$ make install
$ cd ../../download
$ wget http://kernel.org/pub/software/scm/git/git-1.7.6.tar.bz2
$ tar jxf git-1.7.6.tar.bz2
$ cd git-1.7.6
$ ./configure --with-curl=/usr/local
$ make
$ make install

しかし、この後にgitでpushしようとしても、何故かgit http-pushのコマンドはありませんと怒られた。どうやらビルドコンパイルがうまくいっていない模様。ここが2つ目のはまり。

$ cd
$ cd git/project
$ git push origin master
$ git: 'http-push' is not a git command.

もう一度gitの方をmake clean、make、make installの順番でやりなおすと、たしかにcurlの部分でno-filesといわれている。気付かなかった。しかし、--with-curlはつけているし、ソースファイルも入っている。ヘッダファイル関係なのかと思い、yumでcurl-develをインストール。

yum install curl-devel

yumでgitインストールしたタイミングでは、git http-pushそのものはコマンドとして認識されていた。つまりこの時点ではcurlの認識はうまくされていたということだと思う。
その後自分でいれたcurlがうまく認識されていない理由がいまいちわからなかった。--with-curlのオプションはつけているし、git http-pushが認識されていないという状態がcurl-develがないが故のものだとすると、最初からコマンドとしてないですよーというエラーが出そうなもの。
なにはともあれ、gitでhttp-pushのコマンドが認識されるようになった。後はgit pushすればOK。

$ cd
$ cd git/project
$ git push origin master

GitでのHTTP通信覚え書き読み取り編

HTTP経由でのGitの通信を設定する上で色々とはまったので、覚え書き。
今回は読み取り編。読み取りに関してはほとんどはまりがなかったけれど、備忘録的につけておく。

目標
HTTP経由で、既存のGitプロジェクトをcloneできるようにする。

例)HTTPサーバ=Apache、起動ユーザ=daemonの場合、リポジトリのパスは適時自分のものを設定

$ cd /your/gitrepos/project.git
$ mv hooks/post-update.sample hooks/post-update
$ chmod a+x hooks/post-update
  • 権限設定(ここではグループユーザを設定しているが、グループユーザに読み取りと実行権限があることが前提)
$ cd /your/gitrepos/project.git
$ chown :daemon 
  • ドキュメントルートの設定

    ServerName git.gitserver
    DocumentRoot /your/gitrepos/
    
        Order allow, deny
        allow from all
    

Apacheの再起動。
クライアント側からgit clone http://git.gitserver/your/gitrepos/project.gitでcloneができれば成功。
ただし、これはフルオープンなので、アクセス制限をかけたいなら適時かける。
また、HTTPプロトコルを通しているので、cloneにかかる時間がGitプロトコルよりも遅い。

Engine Yard AppCloudのTrial

Engine Yard AppCloudをTraialで使ってみた。

Engine Yard AppCloudとはHerokuと同様、AmazonのEC2上で動かしているクラウドサービス。

Herokuとどこが違うのかをざっくりまとめてみる。細かい部分での違いはいくつもあるけれど、大きく感じたのは以下の点。

  • Gitのリポジトリサーバは自分で持つ。
  • Ruby On Railsだけでなく、Merb,Sinatraも動かせる。
  • Deployはサービスページから。つまりはGUIベース、gitにpush=deployとはならない。
  • 一つのアプリケーションに対して複数の環境を作れる。

 例:アプリケーション名;blog
production環境、staging環境、ci環境、development環境

  • サーバのステータスをCactaiのようにグラフ監視できる。CPU,LoadAverage,Memcache利用率といった、パフォーマンスの監視ができる。
  • サービスページからGemの追加、DBのバックアップ、システムのスナップショットがとれる。バックアップとスナップショットに関しては、定期処理に登録できる。

(全部使い切ったわけではないので、間違っている部分があるかもしれない。)

今回作ったのもの
・PracticeManagerというRails3アプリ

  • ユーザ名+twitterアカウント+自分のTODOを登録する。
  • TODOには実行中、終了、未着手のステータスを用意。
  • 実行中のTODOに対して、定期的に応援メッセージをtwitter経由で送る。

今回、TwitterBotとユーザの登録まで作って、Trialの期限を迎えてしまった。
でも、一番やりたかったdeployとサーバステータスの確認ができた。
deployしてみてわかったのは、deployログをみるとHTTPサーバはNginxと使っている模様。Applicationサーバは、Passenger,Mongrel,Unicornから選べる。環境毎にHTTPサーバは変更できる。

deploy作業をGUIでやるのはさほど違和感はなかった。deploy前にスナップショットを自動取得してくてれているし、デプロイのログが都度残るため結構安心。

今回は無料版で使ったけれど、本番サービスでのミニマム使用を想定してWebサーバ2台、DBサーバ2台+基本サポート(データのセキュリティ管理)をつけて見積もってみた。

毎月$1800、20万弱の経費。サービスのスケールアウト、サービス環境構築の削減コストも考えると、普通のデータセンターを使ってインフラ周りのエンジニアを揃えるよりも遥かに安いと考えられる。
後はリスクとのトレードオフで、どこまで使うかを考えればいいと思うんだ。
例えば、大学の研究室とかでアカウントを持っておいて、研究室の学生に好き勝手使わせるとかは結構良いんじゃないかと思う。

Rackサーバ、Powのインストール

Railsのローカルアプリでアプリを立ち上げにしたままにしていたりすることが結構ある。
そんな中で、Rails Hub情報局さんの記事Mac OS X用のRackサーバPowの存在を知った。

Rackサーバと記載されているけれど、実際はRackサーバであるとともにサーバマネージャでもあると思う。Officialサイトを見たところ0 Configのポリシーで、インストール→利用まで設定はほぼ0。
より具体的にいうなら、最小の実行コマンドは下記の3行。


$ curl get.pow.cx | sh
$ cd ~/.pow
$ ln -s /path/to/myapp

例えば、自分のMac環境でRailsのアプリblogを起動させるとする。
今まではhttp://localhost:3000でアクセスしていたのが、http://blog.devとかでアクセスできるようになる。

まだ試していないけれどアプリ単位でworker数とタイムアウト(アクセスがなかった場合にアプリを落とす)の設定もできる。


#~/.powconfig
export POW_TIMEOUT=300000
export POW_WORKERS=3

クラウドサービスが普及して、ローカルでガリガリ開発しなくても別にいい時代になってきたと思う反面、サーバーで試す前に自分のローカルでごにょごにょしたいという人は少なくないはず。
/etc/hostを変更するよりもシンプルに思えるし、管理しやすいと思う。