はじめに
carrierwaveでpdfファイルを投稿し、そのファイルをクリックするとファイルを開く機能があります。
今回は、ファイルをローカル上のpublicディレクトリに保存しているためurl直打ちでファイル表示がされる対策のために、保存先をpublicディレクトリから変更し、ファイルのパスから直接取得するのではなくアクション経由で取得する方法に変更してurl直打ちで表示するのを防ぐ対応をしました。
carrierwaveでのファイルの投稿機能などについては今回のテーマの趣旨とは違うため省略します。
環境
ruby 3.1.2p20
Rails 7.0.4
テーブル
Posts |
---|
name |
file |
コントローラー
app/controllers/posts_controller.rb
def show_file
file_path = Rails.root.join('uploads', 'post', 'file', params[:id], "#{params[:file_identifier]}.pdf") # ローカルに保存されているファイルのパス。保存先に合わせて変更する。
if File.exist?(file_path) # ファイルがある場合
send_data File.read(file_path), type: Mime::Type.lookup_by_extension(File.extname(file_path).delete('.')).to_s, disposition: 'inline' # send_dataでファイルを表示します。
else # ない場合
render plain: 'ファイルが見つかりません', status: 404
end
end
ルーティング
config/routes.rb
resources :posts do
member do
get 'show_file/:file_identifier', to: 'posts#show_file', as: :show_file # urlに:file_identifierを含めることでposts#show_fileでファイル名を取得できるようにします。
end
end
view
post.html.erb
# :file_identifierのパラメータに@post.file.identifierを渡すことでリンク先のposts#show_fileで:file_identifierを扱えるようにします。
<td><%= link_to @post.file, show_file_path(file_identifier: @post.file.identifier) %> </td>
最後に
これでリンクをクリックするとファイルが画面に表示されます。
アクションを経由して表示するため、ログインチェックやユーザーチェックなども実装できるようになりました。
本来はファイルはS3などにアップロードするのが一般的かもしれませんが、ローカルにファイルをおく場合はこのように実装していくのがいいのかなと思いました。
他にもっと良い実装方法はいくらでもあるとは思いますが、ひとまずこれで形にはなるかと思います。
この投稿に不手際や実装のアドバイスがありましたら、コメントいただけますと幸いです。