Nginx の X-Accel-Redirect を Rails で使う

 Nginx で認証つきで大容量ファイルをダウンロードさせたい時は、X-Accel-Redirect を使います。Rails のファイル操作を介さず、Nginxで直接クライアントへデータを送れます。Lighttpd とか Apache でいうところの、X-sendfile と同じような感じでしょうか。
Lighttpd の場合はこちら -> Rails&Lighttpdで大容量ファイルをダウンロード【変なヤバいもんログ内】

 ヘッダに、X-Accel-Redirect でパスを指定して、そのパスを Nginx 側で受けるだけですinternal って付けるのがポイントです。そうすると、このように内部からしか参照できなくなります。外からそのパスを叩いても見れないということになります。

 Rails2以前の場合は自分でヘッダに値を設定する必要があり、Rails3以降は設定を変更するだけでいけるようです。

# Rails2以前
def download
  # 認証処理などを挟むことができます。  
  path = "/bigfiles/long_movie.mp4"
  response.headers['X-Accel-Redirect'] = path
  response.headers['Content-Type'] = "application/force-download" 
  response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(path)}\"" 
  response.headers['Content-length'] = File.size(RAILS_ROOT + path)
  render :nothing => true
end
 
# Rails3
def download
  # 認証処理などを挟むことができます。  
  path = "/bigfiles/long_movie.mp4"
  send_file path, 
             :type => "application/force-download",
             :disposition => "attachment; filename=\"#{File.basename(path)}\""
end
 
# config/environments/production.rb
# 下記行をコメントアウト (Apache, lighttpd の場合はこの行を使う)
# config.action_dispatch.x_sendfile_header = "X-Sendfile"
# 下記の行を有効にする (nginxの場合はこの行を使う)
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
location / {
    client_max_body_size    200m;
    proxy_read_timeout 60;
    proxy_connect_timeout 60;
    proxy_pass http://railsapp;
}

location /bigfiles {
    # -> /path/to/railsroot/bigfiles
    root /path/to/railsroot/;
    internal;
}

gist に上げてあります。https://gist.github.com/708959

補足

 逆に、ちょっとしたアプリを動かすときに、いちいち nginx の設定とかせずに Unicorn とかから直接ファイルを送りたい場合もあります。Rails3になってから、config/environments/productioin.rb がデフォルトのままだと send_file すると 0bytes になってしまいます。

 下記の2行をコメントアウトしておくと、Unicorn なりで直接ファイル送信ができるようになります。

# config.action_dispatch.x_sendfile_header = "X-Sendfile"
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

 ついでに、静的ファイルも Unicorn なりで表示したいような手抜き構成のときは、下記の設定もお忘れなく。

config.serve_static_assets = false
Nginx の X-Accel-Redirect を Rails で使う

accepts_nested_attributes_for のメモ

 忘れやすいので、 accepts_nested_attributes_for の使い方についてメモ。

 Company に複数の Employees がいるとき。

class Company
has_many :employees
accepts_nested_attributes_for :employees
end
 
class Employee
  belongs_to :company
end

View で、下記のように fields_for を使う。Company作成時に、1人の Employee を同時に作る時の例

< %= form_for @company do |f| %>
  name < %= f.text_field :name %><!-- Company の name -->
  < %= f.fields_for :employees do |employee_form| %>
    employees name %lt;%= employee_form.text_field :name %><!-- Employee の name -->
  < % end  %>
  < %= f.submit "Create" %>
< % end %>

コントローラでは、特に何もしなくていいです。

def create
  @company = Company.create!(params[:company])
  redirect_to @company
end
accepts_nested_attributes_for のメモ

Objective-C で base64エンコード

 Objective-C で base64エンコードする方法を調べていたけど、特にこれといったライブラリもないようです。

 Any base64 library on iphone-sdk? のスレッドで、カテゴリを使って NSString に機能を拡張しているサンプルがありました。ただ、そのままだと上手くエンコード出来なかったので、若干修正して github に置いておきました。

 ソースコード -> ecpplus / objective-c-lib / base64

Objective-C で base64エンコード