こんにちは!鳥貴士です!
今回はRails5.2から追加されたActiveStorage機能を使ってファイルのアップロード、そしてダウンロードリンクの実装をします!
具体的にはpdfファイルのアップロード、ダウンロードを行います。
イメージとしてはユーザーがたくさんのpdfモデルを持っている、そのpdfモデルには1つのpdfファイルが割り当てられる感じです。
pdf以外でもできますが、今回作ったものがpdf絡みのものだったのでこんな例になってます。
この例でのファイルの保存先はlocalですが、AWSやGCPなどを使うことも可能です。
セットアップ
まず最初にRailsにActiveStorageのためのテーブルを作成します。
$ rails active_storage:install
$ bundle exec rake db:migrate
を実行し、activestorage_blobとactivestorage_attachmentテーブルが作成されていることを確認します。
マイグレーションに関しては飛ばします。
マイグレーションは見なくてもActiveStorageはわかります。
モデルの設定
テーブルが作成出来たら個々のモデルの設定に移りましょう。
ユーザー
まずユーザーはたくさんのpdfを持っている仕様でしたね。
ですからユーザーモデルは以下のような関係性を保持しています。
これはActiveStorageとは関係のない普通のコードです。
ログインとかパスワードとかは関係ないので省略。
class User < ApplicationRecord has_many :pdfs end
pdfモデルには一つのpdfファイルが紐づけられています。
そしてpdfの所有者すなわちアップロード者はただ一人です。
ですからpdfモデルは以下のような関係性を保持しています。
ただなぜoptional: trueを指定したのかは忘れてしまった。
確かアップロード周りでこけていたはず。
class Pdf < ApplicationRecord belongs_to :user, optional: true has_one_attached :pdf_file end
ルーティングの設定(抜粋)
見ればわかる
get "upload", to: "pdf_upload#new" post "upload", to: "pdf_upload#create" resources :uploaded_pdfs, only: [:index] do end
コントローラの設定
諸々のページについては省略して、アップロードとダウンロードに関係するコントローラのみ取り上げます。
まずはアップロードから。
class PdfUploadController < ApplicationController
def new
@pdf = Pdf.new
end
def create
@pdf = Pdf.new(upload_params)
if @pdf.save
redirect_to uploaded_pdfs_path
end
end
private def upload_params
params.require(:pdf).permit(:user_id, :name, :details, :pdf_file)
end
end
という感じ。
newメソッドは説明いらないでしょ。
createメソッドでupload_paramsを通ってきたデータをデータベースに保存し、完了したら自分がアップロードしたものをみられるページに飛びます。
アップロードしたものがみられるページでは、アップロードしたファイルのダウンロードが可能です。
ダウンロード側のコントローラはこのようになっています。
class UploadedPdfsController < ApplicationController
def index
@pdfs = @current_user.pdfs
end
end
です。説明ほぼいらないですよね。
Userモデルに定義されたhas_many :pdfsの関係ということぐらいです。
ビューの設定
View周りは結構苦手なんですよね。
form_withのオプションわけわからん、書き方何通りあるの。
あとerbなのでタグが<%…%>とか<%=…%>なのも慣れない。
かといってangularみたいになるのもインポートしたりまわりが面倒だし…
まぁ使っているうちに慣れるのはわかってますけどね。
Haml使えっていうのもわかります、言われたことないけど。
言ってることはわかり哲也ですがやる気がでません。
さぁ文句はここまでにしてコードを見ましょう。
アップロードページ
余計なコードは消したのですっきりしています。
<%= form_with model: @pdf, url: upload_path do |f| %>
<div>
<%= f.label "name" %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label "details" %>
<%= f.text_area :details %>
</div>
<div>
<%= f.label "select" %>
<%= f.file_field :pdf %>
</div>
<%= f.hidden_field :user_id, value: @current_user.id %>
<%= f.submit "send" %>
<% end %>form_withでフォームを生成しています。
file_fieldでファイルを指定、hidden_fieldでuser_idをくっつけてsubmitします。
form_withに何も指定しないとpostとして送信されるので、フォームで生成されたデータはPdfUploadController#createに投げられます。
ダウンロードページ
@pdfsはログイン中のユーザーがアップロードしたpdfの配列を返します。
そのためイテレータで処理します。
<% @pdfs.each do |pdf|| %> <%= link_to pdf.name, rails_blob_path(pdf.pdf_file) %> <%= pdf.details %> <% end %>
という具合です。
リンクを生成するためにlink_toを使い、どこからファイルを持ってくるのかはrails_blob_pathメソッドに対してattachしているファイルを指定してあげればよいです。
これでファイルのアップロード、そしてダウンロードリンクの生成ができるようになりましたね!
それではまた!








コメント