画像データのValidation
本番環境の画像保存先を用意する前に、画像のValidationがまだだったので、Userモデル等と違って、ImageUploaderを使いValidationを実装した。
ImageUploaderでの定義
ymlファイルでメッセージの定義
参考
https://qiita.com/IKEA_dless/items/f8f2dc27ed2356da4e50
http://arthurxxx.hatenablog.com/entry/2018/03/08/222925
画像アップロード先をAmazonS3に変更
Herokuは立ち上げるたびに、仮想サーバが作り変えられてしまうためherokuローカル上に保存された画像は消えてしまう。そこで外部のストレージサービスを利用する必要があり、Rails Tutorialでもお勧めされているAmazon S3が一番信頼性も高くエラー時のドキュメントも豊富なことから選択した。
大まかな流れ
(前提)・・・画像アップローダやリサイズの機能が実装されていること。
1 gem 'fog-aws'のインストール
-AWS側の設定
2 IAMユーザの作成(Cloud9で作ったのと手順はほぼ同じ。ユーザ作成して権限を付与)
S3へのFull Access権限を選択。
3 Bucketの作成
Bucketのパケットポリシーの設定でInvalid Principal Errorが出たが、文法上のエラーだった。12桁のIDにハイフンは要らず、そのままユーザのARNをコピーしてPrincipalに添付して解決。
-Rails側の設定
4 config/initialize/carrierwave.rbのファイルの作成及び設定
config.asset_hostにはバケット名ではなく、下記のようにHTTPからのものを環境変数に定義する。
Access Diniedの原因はこれだった。
参考
https://qiita.com/tktcorporation/items/ec2dbc2fe540e313f917
https://qiita.com/yukiyukimiyaiwa/items/a9e0103c8342b81f6ac1
5 4で使う環境変数を定義
heroku config:set AWS_S3_BUCKET = "" で定義
heroku config:get AWS_S3_BUCKET で中身を確認
詳しいフローは、下記のサイトを参照した。
https://morizyun.github.io/infrastructure/aws-s3-with-iam-policy.html
https://morizyun.github.io/ruby/rails-function-form-carrierwave-fog-s3.html
https://remonote.jp/rails-carrierwave-fog-s3
発生した問題
1 Access Dinied
上述したとおり、config.asset_hostの環境変数の定義が問題で、バケット名だけでなく、HTTPからのものを格納することで解決した。
2 サムネイルだけ表示されない
S3への画像アップロードもS3側で問題なくできていることが確認できたが、アプリ側でサムネだけが表示されなかった。
アプリ側で生成されたHTMLソースからサムネのリンクに飛ぶと、上のようなエラーが表示されてしまう。
バケットへのアクセス権限等の問題は、同じ階層にあるサムネではない画像は表示されていることから考えにくかったため、それ以外の原因を考え、生成されたHTMLソースとバケットに表示されるソース(オブジェクト URL)を比較してみた。
例えばjpgファイルをアップロードすると、次のような挙動になった。(ImageUploarderはすべてpngに変換する設定をしてある)
サムネイル画像の生成されたソースはファイルの拡張子が.jpgであるのに対し、バケット側では.pngだった。サムネではない画像表示の方は、生成ソースはjpgでバケット側もjpgであるため表示された。つまり拡張子が違っていたため、URL自体も異なるものにアクセスして弾かれていたということである。
とりあえずの解決策として、ImageUploaderのその設定をコメントアウトすることで、保存される形式とあげた時の形式に齟齬がないようにしたところ、しっかりとサムネイルも表示されるようになった。
残る疑問
なぜpngとして保存する設定がサムネイルにのみ適用されていたのか、また、保存時はpngとして保存したはずなのになぜHTMLの表示ではpngで表示されてしまっていたのか。
修正
グラフ削除
何もデータがないのにグラフ削除のアクションが実行されたときの対策がされていなかったので実装した。
if Graph.findとかで存在自体をチェックしていれば問題がないのだが、それがされていなかったのでその点追記した。
これで複数タブで開き、片方で削除後、また別のタブで削除リンクを押されても問題ない。