はじめに
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
<%= 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
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 メソッドを利用することでことで出来ます。
def read(length=nil, buffer=nil)
@tempfile.read(length, buffer)
end
そして、取得したバイナリデータを保存します。
ファイル名は @original_filename から取得しています。
以上で、ファイルのアップロードが出来るようになりました。
ActionDispatch::Http::UploadedFile クラスについては、以下の記事を参考にさせていただきました。ありがとうございました。
ActionDispatch::Http::UploadedFileを読む (デバックメモ)