Edited at

Rails でファイルをアップロードしてDBに登録する

More than 5 years have passed since last update.


はじめに

gem を使わずに Rails の機能だけで、ファイルのアップロードを試してみます。

バージョン


  • ruby 2.0.0p247

  • Rails 4.0.0

今回は、アップロード可能な形式やファイルサイズの制限はしてません。


Model

class CreateContents < ActiveRecord::Migration

def change
create_table :contents do |t|
t.string :upload_file_name
t.binary :upload_file

t.timestamps
end
end
end

モデル名は Content としています。

アップロードされたファイルを保存する upload_file をbinary、ファイル名を保存する upload_file_name を string で定義しています。


View


index.html.erb

<%= form_for(@content) do |f| %>

<div class="field">
<%= f.file_field :upload_file %>
</div>
<div class="actions">
<%= f.submit "Upload" %>
</div>
<% end %>

file_field を配置して、アップロードする form を作成する。


Controller


contents_controller.rb

  def create

upload_file = content_params[:upload_file]
content = {}
if upload_file != nil
content[:upload_file] = upload_file.read
content[:upload_file_name] = upload_file.original_filename
end
content[:password] = content_params[:password]
@content = Content.new(content)
respond_to do |format|
if @content.save
format.html { redirect_to @content, notice: 'Upload success' }
format.json { render action: 'show', status: :created, location: @content }
else
@contents = Content.all
format.html { render action: 'index' }
format.json { render json: @content.errors, status: :unprocessable_entity }
end
end
end

create アクションに処理を書いていきます。

アップロードされたファイルの取得方法については、railsdoc の「アップロードされたファイルを取得」に詳しく載ってます。

content_params は strong_parameter です。

注意しなければいけないのは、アップロードされたファイルを直接DBに保存しようとするとエラーになります。

アップロードされたファイルは、 ActionDispatch::Http::UploadedFile クラスのオブジェクトであ

り、以下のようなインスタンスになっています。

#<ActionDispatch::Http::UploadedFile:0x007fe7ad501990

@content_type="text/plain",
@headers=
"Content-Disposition: form-data; name=\"content[upload_file]\"; filename=\"test.txt\"\r\nContent-Type: text/plain\r\nContent-Length: 15\r\n",
@original_filename="test.txt",
@tempfile=
#<File:/var/folders/bg/3rk9r1y94_126k3231h0hvn40000gn/T/RackMultipart20131129-17450-zqlkd1>>

ファイル本体を取得するためには、@tempfile を read する必要があるんですが、UploadedFile クラスの read メソッドを利用することでことで出来ます。


ActionDispatch

def read(length=nil, buffer=nil)

@tempfile.read(length, buffer)
end

そして、取得したバイナリデータを保存します。

ファイル名は @original_filename から取得しています。

以上で、ファイルのアップロードが出来るようになりました。

ActionDispatch::Http::UploadedFile クラスについては、以下の記事を参考にさせていただきました。ありがとうございました。

ActionDispatch::Http::UploadedFileを読む (デバックメモ)