複数バージョンのrubyを共存させるツールとして、過去にはRVMを使っていたが少し前にrbenvに変えた。
Rails3世代になり、RVMのgemsetはbundlerで代替可能になったので、RVMの豊富な機能が少し邪魔に感じたので。同時に、サーバーサイドでも管理が簡単なのでrbenvを使うようにした。あまり推奨はされてないようだけど。

rbenvの通常インストール方法はsstephenson/rbenv – GitHubにあるのでそちらを参照するとよい。

また、rbenvで使うrubyインストーラーであるsstephenson/ruby-build – GitHubも一緒に使うとすごく便利。

以下、サーバーで行った作業のログをメモ。


# rbenvインストール
$ git clone git://github.com/sstephenson/rbenv.git /usr/share/rbenv

# profile.dにrbenvの設定を追加
$ vi /etc/profile.d/rbenv.sh
# ここから
export PATH="/usr/share/rbenv/bin:$PATH"
export RBENV_VERSION=ree-1.8.7-2011.12
export RBENV_DIR=/usr/share/rbenv
export RBENV_ROOT=/usr/share/rbenv
eval "$(rbenv init -)"
# ここまで

# /etc/profile.d/rbenv.shに実行権限を与える
$ chmod 755 /etc/profile.d/rbenv.sh

# 一旦上記設定を読み込む
$ source /etc/profile.d/rbenv.sh

# ruby-buildインストール
$ git clone git://github.com/sstephenson/ruby-build.git
$ cd ruby-build
$ ./install.sh

# 今回はREE1.8.7をインストール
$ rbenv install ree-1.8.7-2011.12

# REE1.8.7をデフォルトで使用する
$ rbenv global ree-1.8.7-2011.12

と、ここまででrbenvのセットアップは完了。動作確認のために、一度シェルを再起動した上でrubyのバージョンを確認してみる。

$ ruby -v
ruby 1.8.7 (2011-12-28 MBARI 8/0x8770 on patchlevel 357) [i686-linux], MBARI 0x8770, Ruby Enterprise Edition 2011.12

正しくREEが使われることが確認できた。あとは、gemでrailsとunicorn_railsをインストールすればよい。

rbenv上のREEでunicornを起動するには、以下のようなスクリプトを作ればよい。

app_root=/var/www/rails_application
rbenv_bin=/usr/share/rbenv/versions/ree-1.8.7-2011.12/bin
cd $app_root && $rbenv_bin/bundle exec $rbenv_bin/unicorn_rails -c $app_root/config/unicorn.conf.rb -e production $app_root/config.ru

普段はUpstartで自動起動などをしているが、その場合 /etc/init/以下に次のような設定ファイルを作ればいい。これは、アプリケーションごとに1つのファイルになるので、例えばアプリケーション名がRailsAppならばRailsApp.confなどとする。

#!/bin/sh
description "Rails Application"
start on runlevel [2345]

script
  app_root=/var/www/rails_application
  rbenv_bin=/usr/share/rbenv/versions/ree-1.8.7-2011.12/bin
  cd $app_root && $rbenv_bin/bundle exec $rbenv_bin/unicorn_rails -c
  $app_root/config/unicorn.conf.rb -e production $app_root/config.ru >> /tmp/upstart.log 2>&1
end script

respawn

このアプリケーションの起動や終了はLinuxの場合ディストリビューションによって変わるが、大体の場合以下のようなコマンドで実行できるので自分の環境に最適なものを選択する。

# 起動
$ sudo service railsapp start
# または
$ sudo initctl start railsapp

# 終了
$ sudo service railsapp stop
# または
$ sudo initctl stop railsapp

UpstartはUbuntu10.04、CentOS6、Amazon Linuxなどで使える。従来の/etc/init.d/以下にあるようなスクリプトよりだいぶシンプルに書けるので積極的に使っている。他にもいろいろとメリットがあるらしいが、正直よくわからない。

 

Ruby on Rails 3.1.0が正式リリースされたので、早速3.1.0RCで作っていたアプリをアップデートしたところproduction環境でassets pipelineが上手く動かなくなったので。

現象としては、stylesheet_link_tagやjavascript_include_tagで出力されるファイルのURLが、RC6だと

<link href="/assets/application-9bfec9e77b13d0aae452fa8f1b785be2.css" media="screen" rel="stylesheet" type="text/css" />
<script src="/assets/application-773d7f39b6aab9114a3b3b034fe6ac17.js" type="text/javascript"></script>

だったのが、stableだと

<link href="/assets/application.css" media="screen" rel="stylesheet" type="text/css" />
<script src="/assets/application.js" type="text/javascript"></script>

になってしまうため、assets:precompileで予めassetsファイルを作る設定であったproduction環境において、cssファイルもjsファイルも見つからずにかわいそうなことになるわけです。
それどころかrake assets:precompileもコケる事態になってました。

これは、3.1.0RC8あたりでassets pipelineに関する変更がいくつか取り込まれた関係で設定項目が増え、デフォルトの挙動が変更になったからですね。詳細はgithubのrailsリポジトリのissuesを見てください。

肝心の修正方法ですが、config/environments/production.rbの14~17行目あたりを以下のように変えるだけでOKでした。

# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true

# Generate digests for assets URLs
config.assets.digest = true

さて、3.1.0がリリースされて2日目ですが、早くもpjax_railsが取り込まれると噂の3.2.0が待ちどおしいです。

 

Rails3からhas_and_belongs_to_manyより柔軟なhas_many thorughというRelationshipができたので試す。ブログの記事を登録する際に、セレクトボックスで複数のカテゴリを選択する場合を想定している。コントローラーやviewについて記述が無い箇所は、scaffoldで生成したコードと同等のもので動くと思う。

まずはmigrationを使ってテーブルを作る。

# ブログ記事
class Posts < ActiveRecord::Migration
  def change
    create_Table :posts do |t|
      t.string :title
      t.text :body
      t.timestamps
    end
  end
end

# カテゴリ
class Categories < ActiveRecord::Migration
  def change
    create_Table :categories do |t|
      t.string :name
      t.timestamps
    end
  end
end

# ブログ記事とタグを繋ぐ中間テーブル
class Categorizations < ActiveRecord::Migration
  def change
    create_Table :categorizations do |t|
      t.references :post, null: false
      t.references :category, null: false
      t.timestamps
    end
  end
end

中間テーブルのカラム名を複数形にしてしまい少しハマッたので注意。次にモデルを定義する。

# ブログ記事のモデル
class Post < ActiveRecord::Base
  has_many :categorizations, dependent: :destroy
  has_many :categories, through: :categorizations
end

# カテゴリのモデル
class Category < ActiveRecord::Base
  has_many :categorizations, dependent: :destroy
  has_many :posts, through: :categorizations
end

# 中間テーブルのモデル
class Categorization < ActiveRecord::Base
  belongs_to :post
  belongs_to :category
end

最後に、ブログ記事の新規登録画面のviewを少し書き換える。

<%= form_for @post do |f| %>
  <%= render '/shared/validation_messages', :model => @product %>
    <div class="field">
      <%= f.label :name %><br/>
      <%= f.text_field :name %>
    </div>
    <div class="field">
      <%= f.label :body %><br/>
      <%= f.text_area :body %>
    </div>
    <div class="field">
      <%= f.label :category_ids %><br/>
      <%= f.select :category_ids, Category.all.map {|c| [c.name, c.id]}, {}, multiple: true %>
    </div>
  </div>
    <div class="actions">
      <%= f.submit 'Launch this product' %>
    </div>
  </div>
<% end %>

これを使うまで知らなかったんだけど、フォームの項目名を複数系にすることでmultipleな入力も受け付けてくれるようなのですごく簡単にこういったことができる。

 

http streamを使ったchunked uploadのとき、webrickとかだとスルーされる。なのでvalums file uploaderとかpluploadとか使ってるとparamsにHttp::UploadedFileが渡されず、ファイル名だけポツンとそこにいて大変寂しい思いをする。

そういうときはrack middlewareを自前で書いてたんだけど、githubでいいのを見つけた。
newbamboo/rack-raw-upload
使い方は簡単で、Gemfileに以下の一行を追加して

gem 'rack-raw-upload', git: 'git://github.com/newbamboo/rack-raw-upload.git'

RAILS_ROOT/config/initializers/rack_raw_upload.rbみたいなものを作って

Rails.application.config.middleware.use Rack::RawUpload

とするだけでよい。

そうするとparams[:file]にHttp::UploadedFileが渡されるようになるので、そのままpaperclipなりcarrierwaveなりが指定するようにparams[:file]をゴニョゴニョするとうまくいく。

ところで今日、Rails3.1RC6がリリースされ、同時にRails3.1のリリース予定日が8/30と発表されたので要チェックです。

Rails3.1RC4でassetsがRoutingError(404 Not Found)になったら

 Rails  コメントは受け付けていません。
7月 262011
 

Rails3.1が楽しすぎて調子にノッてたらちょいハマリしたので。
Rails3.1RC4とSprockets2.0.0.beta.11以降の相性が悪いらしく、これらのバージョンを使うとassets/以下のcssやjsが全てRoutingErrorで404 Not Foundになってしまいます。
sprocketsのissueには上がっていないので不確実ですが、bundle update等してしまうと発症する模様です。
幸いSprockets2.0.0.beta.10以前なら問題なく動きますのでGemfileを以下のようにすれば解決します。

# RAILS_ROOT/Gemfile
gem 'sprockets', '= 2.0.0.beta.10'

Rails3.1楽しすぎるのでみんなやるといいと思う。

© 2011 sanojimaru.com Suffusion theme by Sayontan Sinha