Rails 4 + Ruby 2.0 で画面遷移無しのファイルアップロード
表題のとおりのサンプルプロジェクトを作成します。
まずはプロジェクトを新規作成します。
rails new sample_upload
scaffold でアップロード機能を作成、この辺はいつもどおり。
bundle exec rails g scaffold attachments title:string path:text
何かと不便なのでルーティングを定義しておきます。
root 'attachments#index'
終わったらマイグレーションを通しましょう。
bundle exec rake db:create bundle exec rake db:migrate
次に app/models/attachment.rb を編集し、ファイルがアップロードできるようにします。
class Attachment < ActiveRecord::Base attr_accessor :file before_create :store_file before_destroy :destroy_file private def store_file self.path = '/attachments/' + self.file.original_filename File.open(full_path, "wb") do |f| f.write self.file.read end end def destroy_file begin File.unlink full_path rescue nil end end def full_path return Rails.root.join('public').to_s + self.path end end
なお、ディレクトリトラバーサルについては考慮していません。
次に app/views/attachments/_form.html.erb を編集します。
<%= form_for(@attachment) do |f| %> <div class="field"> <%= f.label :title %><br> <%= f.text_field :title %> </div> <div class="field"> <%= f.label :file %><br> <%= f.file_field :file %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
これでファイルをアップロードできるようになりました。なお Rails 4 では内部に file_field を含むフォームについては自動的に multipart オプションをつけてくれるようになっています。
せっかくなので app/views/attachments/index.html.erb と app/views/attachmnets/show.html.erb を編集してアップロードした画像が表示されるようにします。
<%= attachment.path %>
これを
<%= image_tag attachment.path %>
こんな風に。
ここまでで普通のアップローダーとして動作可能なはずなので、動作を確認します。問題なければ次へ。アップロードフォームを画面遷移無しにします。
まずはプラグインを下記サイトからダウンロードします。使い方についてもまとまっているので、確認してください。
http://jquery.malsup.com/form/
ダウンロードしたファイルは app/assets/javascripts 以下に配置します。
次に app/assets/javascripts を編集します。
$(document).on('page:change', function() { var options = { success: showResponse } $('#new_attachment').ajaxForm(options); }); function showResponse(responseText, statusText, xhr, $form) { alert('status: ' + statusText + '\n\nresponseText: ' + responseText); }
とりあえずレスポンスは alert で表示するだけにしました。
また Rails 4 以降では turbolinks が標準化されているので $() {} を普通に使ってもイベントが正しく発生しません。詳しくは github のドキュメントで確認してください。
https://github.com/rails/turbolinks/blob/master/README.md
app/controllers/attachments_controller.rb を編集し JSON で値を返すようにします。
def create @attachment = Attachment.new(attachment_params) if @attachment.save render json: @attachment else render json: @attachment.errors, status: :unprocessable_entity end end
ここまでで今回のサンプルは作成完了です。