LoginSignup
0
1

More than 1 year has passed since last update.

【Ruby on Rails】GUI でのアップロードを介さず CarrierWave にファイルを保存する方法

Posted at

Rails アプリで画像などのファイルを保存したいと思った際、有力な候補として上がる gem としては CarrierWave などが挙げられるでしょう。

で、多くの記事においては

./app/uploaders/file_uploader.rb
class FileUploader < CarrierWave::Uploader::Base
  storage :file
end
./app/models/post.rb
class Post < ApplicationRecord
  mount_uploader :file, FileUploader
end
./app/views/posts/_form.html.erb
<%= f.file_field :file %>
./app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def create
    post = Post.new(post_params)
    post.save!
  end

  private

  def post_params
    params.require(:post).permit(:file)
  end
end

といった GUI でのアップロードを前提としたやり方が説明されていると思います。

しかし、コード上で生成したファイルを CarrierWave に保存する場合、どうすれば良いのか...。気になったので調べてみました。

たとえば、以下のようなケースでこのやり方は有効になると思います。

  1. 何かしらのサービス(運営とユーザーが存在)を想定
  2. 管理画面から「ユーザーに〇〇(PDF)を送信」というボタンを押す
  3. その場で PDF ファイルが自動生成され、ダイレクトメッセージ(DirectMessage)に添付してユーザーに送信

「PDF ファイルが自動生成され」 という部分がキモです。ここが「GUI でのアップロードを介さずに」が意味するところですね。

StringIO クラスを使用

結論から言うと、StringIO クラス を使います。
参照: RubyのStringIOから値を回収する

まず、StringIo クラスを継承した CarrierwaveStringIO というクラスを作成。

./lib/carrierwave_string_i_o.rb
class CarrierwaveStringIO < StringIO
  def initialize(filename, content_type, data)
    super(data)
    
    @filename = filename
    @content_type = content_type
  end 

  def original_filename
    @filename
  end

  def content_type
    @content_type
  end
end

あとは次のような感じで実装していけば OK です。
あくまでイメージなので、適宜自分のコード向けに調整してください。

./lib/pdf_generator.rb
# PDF の生成には Prawn(gem) を使用するのを想定
# https://github.com/cortiz/prawn-rails
class PdfWorkingConditionNoticeGenerator < Prawn::Document
  def initialize
    super(
      page_size: "A4",
      margin: 20
    )

    font Rails.root.join("app/assets/fonts/mplus-2p-regular.ttf")

    header
    move_down 30
    
    contents
  end
  
  private

  def header
    text "Test PDF"
  end

  def contents
    text "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  end
end
./app/models/direct_message.rb
class DirectMessage < ApplicationRecord
  mount_uploader :file, FileUploader

  # GUI からアップロードされたファイルではなくコード上で生成したファイルを carrierwave に渡すためのメソッド
  def attach_file_not_via_gui_upload(filename, content_type, data)
    self.file = CarrierwaveStringIO.new(filename, content_type, data)
  end
end
./app/controllers/direct_messages_controller.rb
class DirectMessagesController < ApplicationController
  def send_pdf_to_user
    direct_message = DirectMessage.new(
      user_id: params[:user_id],
      body: "〇〇(PDF)を送信しました"
    )
    
    filename = "test.pdf"
    pdf = PdfGenerator.new
    
    direct_message.attach_file_not_via_gui_upload(filename, "application/pdf", pdf.render)
    direct_message.save!
  end
end

あとがき

以上、GUI でのアップロードを介さず CarrierWave にファイルを保存する方法でした。
同じような疑問を抱えていた人は参考にしてみてください。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1