LoginSignup
masa0720
@masa0720 (まさ)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

本番環境:minimagickを使って投稿したい

質問内容・実現したいこと

本番環境でユーザーが投稿した画像とs3に保存
している額縁の画像をminimagickで合成して投稿できるようにしたい。

環境

Rails7
minimagick
s3
fly.io

現状発生している問題・エラーメッセージ

本番環境で新規投稿すると以下のようなエラー発生します。

2023-09-05T09:24:30Z app[17811616a41618] nrt [info]I, [2023-09-05T09:24:30.077038 #255]  INFO -- : [03f2de85-4403-45e5-bae5-07b13374df5f]   Parameters: {"authenticity_token"=>"[FILTERED]", "post"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x00007fc3954f69f0 @tempfile=#<Tempfile:/tmp/RackMultipart20230905-255-v4bwig.png>, @content_type="image/png", @original_filename="sample.png", @headers="Content-Disposition: form-data; name=\"post[image]\"; filename=\"sample.png\"\r\nContent-Type: image/png\r\n">, "title"=>"sample", "body"=>"sample", "status"=>"published"}, "commit"=>"OK"}
2023-09-05T09:24:30Z app[17811616a41618] nrt [info]I, [2023-09-05T09:24:30.271116 #255]  INFO -- : [03f2de85-4403-45e5-bae5-07b13374df5f] Completed 500 Internal Server Error in 194ms (ActiveRecord: 1.4ms | Allocations: 3300)
2023-09-05T09:24:30Z app[17811616a41618] nrt [info]F, [2023-09-05T09:24:30.271857 #255] FATAL -- : [03f2de85-4403-45e5-bae5-07b13374df5f]
2023-09-05T09:24:30Z app[17811616a41618] nrt [info][03f2de85-4403-45e5-bae5-07b13374df5f] Errno::ENOENT (No such file or directory @ rb_sysopen - uploads/tmp/1693905870-746540478756659-0002-6026/sample.png):

動いている処理

本番環境で画像合成なしの投稿(add_frameメソッドを使用しない)は成功できています。その際のs3の保存先はuploads/post/image/数字/画像データです。
開発環境で画像合成ありで投稿は成功できています。

該当のソースコード

  • post.rb
class Post < ApplicationRecord
  mount_uploader :image, ImageUploader
  before_save :add_frame
  has_one_attached :image
  validates :image, presence: true

  private

  def add_frame
    return unless image.present?

    input_path = image.path
    frame_path = Rails.configuration.frame_image_path
    image = MiniMagick::Image.open(input_path)
    image.resize "210x280!"
    frame = MiniMagick::Image.open(frame_path)
    frame.resize "210x280!"
    result = image.composite(frame) do |c|
      c.compose "Over"
    end
    output_filename = "#{Time.now.to_i}.png"
    output_path = Rails.root.join("public", "uploads", "post", "image", output_filename)
    result.write(output_path)
    self.compose_image = "/uploads/post/image/#{output_filename}"
  end
end
  • postscontroller
class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  def index
    @posts = Post.published.order(created_at: :desc).page(params[:page]).per(10)
  end

  def show; end

  def new
    @post =Post.new
  end

  def create
    @post = current_user.posts.build(new_post_params)
    if @post.save
      redirect_to index_path
    else
      @post = Post.new(new_post_params)
      flash.now[:danger] = "未入力があります。写真、題名、投稿内容すべて入力してください。下書きにするときも何か入れてください"
      render 'new'
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:body, :image, :status, :title, :empathy,:compose_image)
  end

  def new_post_params
    params.require(:post).permit(:body, :image, :title,:status,:compose_image)
  end
end

  • pruduction.rb
  config.frame_image_path = 'https://museum1-app.s3.amazonaws.com/uploads/額縁.png'

エラーから考えられる原因

1,Errno::ENOENT (No such file or directory @ rb_sysopenとあることから権限を与えることができていない。
2,新規投稿時compose_imageカラムがない。

試したこと

1,権限を与えるために以下のように行い再デプロイしましたが、エラー解消できませんでした。

 % chmod 777 /museum_app/public/uploads
 % ls -l                                                                      
total 0
drwxrwxrwx@  4 username  staff   128  8 23 18:19 post
drwxrwxrwx@ 87 username  staff  2784  9  5 18:40 tmp

2,postモデルにはcompose_imageが存在している。
開発環境で新規投稿すると["compose_image", "/uploads/post/image/1693906839.png"]と画像データが入っているので、パラメータの付与は正しくできている。本番環境でもデータが入るように工夫すべきだが、手段がわからない。

以上となっております。
ご教示いただけますと幸いです。

0

2Answer

1,Errno::ENOENT (No such file or directory @ rb_sysopenとあることから権限を与えることができていない。

権限の問題ではなくファイルまたはディレクトリが存在しないというエラーです。エラーが出ているパス uploads/tmp/1693905870-746540478756659-0002-6026/sample.png が何に由来するかコードからは分からないため直し方は提示できませんが、これが存在するように修正してください。

なお、 Fly.io のストレージに保存したファイルは再デプロイなどで VM が再起動すると消えます。 それによってファイルが消えている場合は、永続ストレージである Fly Volumes の利用を検討してください。

1

Comments

  1. @masa0720

    Questioner

    権限の問題ではなくファイルまたはディレクトリが存在しないというエラーです。

    ご指摘いただいた通り、ファイルやディレクトリがないというエラーでした。
    見当違いの修正をしておりました。ご指摘ありがとうございます。

    エラーが出ているパス uploads/tmp/1693905870-746540478756659-0002-6026/sample.png が何に由来するかコードからは分からないため直し方は提示できませんが、これが存在するように修正してください。

    コメントいただいた何に由来するかコードからは分からないという点に上手く返信できているか分かりませんが以下の通りに考えております。
    エラーが出ているパスですが、こちらでは想定していないパスに保存しようとしております。
    私の想定では、postモデルのadd_frameメソッドにある、"/uploads/post/image/#{output_filename}"に保存したいと考えています。こちらの保存先ですが、本番環境の額縁を合成しない(add_frameメソッドをコメントアウト)投稿では、s3の"/uploads/post/image/#{output_filename}"に保存されます。その際s3にpostなどのディレクトリがない状態からpost以下が作成され、保存されていました。


    現状

    開発環境 add_frameなし:新規投稿成功
    開発環境 add_frameあり:新規投稿成功
    本番環境 add_frameなし:新規投稿成功
    本番環境 add_frameあり:新規投稿失敗

以下の修正で合成できました。
add_frameのどこまでが成功しているのか切り分けて作業することで解消できました。
みなさま、ありがとうございます。

post.rb
class Post < ApplicationRecord
  require 'aws-sdk-s3'
  mount_uploader :image, ImageUploader
  before_save :add_frame

  private

  def add_frame
    return unless image.present?

    # 投稿画像のパス
    input_path = image.url
    # 額縁画像のパス
    s3 = Aws::S3::Resource.new(region: 'ap-northeast-1')
    obj = s3.bucket('バケット名').object('アップロードした画像のkey')
    url = obj.presigned_url(:get)
    Rails.logger.info "frame_path"
    # 投稿画像を読み込む
    image = MiniMagick::Image.open(input_path)
    image.resize "210x280!"
    Rails.logger.info "image open"
    # 額縁画像を読み込む
    frame = MiniMagick::Image.open(url)
    frame.resize "210x280!"
    Rails.logger.info "frame open"
    # 投稿画像と額縁画像を合成する
    result = image.composite(frame) do |c|
      c.compose "Over"
    end
    Rails.logger.info "compose_ok"
    # 合成した画像を保存する
    output_filename = "#{Time.now.to_i}.png"
    output_path = Rails.root.join("public", "uploads", "post", "image", output_filename)
    result.write(output_path)
    self.compose_image = "/uploads/post/image/#{output_filename}"
    Rails.logger.info "outpath_ok"
  end
end
0

Your answer might help someone💌