Ruby
Rails

インターン 4日目(2月1日)

TODO

  • 管理画面から申し込み一覧、申し込み詳細にいける。
  • そこから写真の納品ができる
  • 写真の納品はただuploadできるだけでなく、一気に複数枚アップロードできる
  • そして、納品一覧ページではアップロードした写真の一枚だけサムネイルとして表示され、クリックするとアップロードした全てのファイルが見れる。
  • 納品してアップロードした写真は,homes/top.html.erbで表示される。

1から行こう

管理画面から申し込み一覧、申し込み詳細にいける。

復習

app/config/routes.rb
...
namespace :admin do
  resources :order
end

/admin/orderから管理画面にアクセスできるようにする。

この場合のコントローラーとビューには気をつけなければならないことがある。
Controllerはadminディレクトリを作成し、その中にorder_controller.rbを作る。
その時に作るClassにも注意、以下のようにする。

app/controllers/admin/order_controller.rb
class Admin::OrderController < ApplicationController
  def index
    @order = Inquiry.all
  end
  def show
    @order = Inquiry.find(params[:id])
  end
end

のようにただ、OrderController < ApplicationControllerにするのではない。
=> Admin::OrderController < ApplicationConrollerのようにする。

Viewもadminディレクトリの中にorderディレクトリを作り、その中にindex.html.erbshow.html.erbを作成する。
こちらは申し込み一覧画面。名前を押すと詳細管理画面へ飛べる。

app/views/admin/order/index.html.erb
<h1>管理画面です</h1>
<% @order.each do |order| %>
  <p>名前</p>
  <span>
    <%= link_to order.name, admin_order_path(order.id) %>
  </span>
  <p>電話番号</p>
  <span><%= order.phone_number %></span>
  <p>メールアドレス</p>
  <span><%= order.mail %></span>
<% end %>

詳細画面から納品画面へを押せば、アップロード画面へ飛べる。

app/views/admin/order/show.html.erb
<h1>詳細管理画面です。</h1>
<h1>名前</h1>
<%= @order.name %>
<h1>電話番号</h1>
<%= @order.phone_number %>
<h1>メールアドレス</h1>
<%= @order.mail %>

<%= link_to '納品画面へ' ,uploader_form_path %>

2. そこから写真の納品ができる。

gemとして、CarrierWaveを利用する

1.Gemfileをインストール

Gemfile
gem 'carrierwave'

$ bundle install

2.uploaderクラスを作成

CarreirWaveでは uploader というジェネレータが提供されるので、任意の名前でクラスを作成。
以下では、uploadfileという名前でuploadクラスを生成。

$ rails g uploader UploadFile
これによって生成されるのは

app/uploaders/upload_file_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base

  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end

画像の保存のために、Storeモデルを作成し、このモデルクラスにuploaderを設定

storeというモデルクラスに、imageというstring型のカラムを追加する。
rails g model store image:string
rails db:migrate

3.storeモデルへuploaderを設定。

mount_uploader :carrierwave用に作ったカラム名, carrierwaveの設定ファイルのクラス名
これによりモデルとの紐付けができるようになる。

app/model/store.rb
mount_uploader :image, ImageUploader

4.ビューの修正

formへファイル選択ボックスを追加
また、バリデーションでエラーが発生し、フォームが再表示された場合もアップロードされたファイルが保持されるようにカラム名_cacheというhiddenフィールドを用意しておく。

=>ここら辺でContollerをいじらなければいけないのだけど、何をやっているのかよくわからなくなった。。。。。。。そもそも参照していたページが、昨日実装したものと違うし、昨日実装したものをどこをどう消したらいいのかさえもわからない。。。。。。。。。
=>次からは、参照したやつを残しておくのと、クソページだと思ったら、今後アクセスするのは時間の無駄でしかないのでブロックしよう。
ゴミサイトにアクセスするのは時間の無駄なのでガンガンブロック

ストロングパラメータをもう一度確認する
requireでモデル持ってきて、permitでカラムを制限するという理解でOK?????

色々あって解決した。
これからはどれを参照したのかきちんとメモって、くそサイトはブロックしておく

どのような仕組みで動いているのかをきちんと理解してから、色々やる必要があると思った。

それでは、以下のことを順番にやっていく。

  • 写真の納品はただuploadできるだけでなく、一気に複数枚アップロードできる
  • そして、納品一覧ページではアップロードした写真の一枚だけサムネイルとして表示され、クリックするとアップロードした全てのファイルが見れる。
  • 納品してアップロードした写真は,homes/top.html.erbで表示される。

CarrierWave 複数の画像をコード三行で一つのカラムに保存する

Storeテーブルにimagesカラムを追加

$ rails g migration add_images_to_store images:json
$ rake db:migrate

ImageUploaderをimagesカラムにマウント

app/model/store.rb
  class Store < ActiveRecord::Base
    mount_uploaders :images, ImageUploader
  end

画像アップロード用のフォームを作成

app/views/upload/index.html.erb
<%= f.label :images, "ユーザー画像" %>
<%= f.file_field :images ,multiple: true%>

strong parametersにimagesに追加

app/controllers/upload_controller.rb
params.require(:store).permit(:{images: []})

=> 実行!!!!
エラー! どうも、Railsに生の状態で登録されているDBであるSQliteには、Json形式が登録されていないらしい。

rails consoleでStoreモデルの中身を調べてみても、imagesのカラム型が登録されていない。
これの解決策として、

app/models/store.rb
class Store < ApplicationRecord
  serialize :images, JSON
  mount_uploaders :images, ImageUploader
end

上のように、serialize :image, JSONを追加すればimagesのカラム型は何型で登録してあったとしても、必ずJSONに変換される。

これで、imagesの型をJSONのままにして色々やっても結局うまくいかず、string型に一応設定しておいたらうまくいった。
この時にDBを弄ったので、暗記事項として復習をしておく。
db:migrateを最初からやり直したい!
最初からやり直すには、

$ rake db:migrate:reset
$ rake db:reset

の二つがある。

  • rake db:migrate:reset
    • db/migrate/*.rb を古い順にあててくれるらしい
  • rake db:reset
    • db/schema.rb でdbを再構築してくれるらしい

rake db:resetの方はよくわからないが、rake db:migrate:resetは全てのマイグレーションの処理を最初から全てやり直してくれる。
こっちの方が良さそう。

ちなみに、rails g migration add_images_to_store images:jsonといったカラムを追加する操作は、migrationファイルを作成してくれるだけで、特に変更が起こる訳ではなく、rails db:migrateを行った際に初めて反映される。

あと、マイグレーションファイル作ろうとしたらidenticalっていうのが出てきたんだけど、これはすでに同じファイルがあるよってことで、実行順番を変えるために作り直すことはできない。

rails db:rollbackっていう機能があって、これはマイグレーションを前の順番に戻せる。またオプションを指定すれば、いくつ前のマイグレーションまで戻すかの変更ができる。

他にDBのconflictとかあったけど、まあそれは無視しよう。

そして、納品一覧ページではアップロードした写真の一枚だけサムネイルとして表示され、クリックするとアップロードした全てのファイルが見れる。

Gemfile
gem 'mini_magick' #を追加する。
app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  #以下は初めからある
  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
   #以下を追加
   #サムネイルのために以下を追加
  include CarrierWave::MiniMagick

  #画像のサイズを変更
  #アップロードすると最大1280×720にリサイズされる。
  process :resize_to_limit => [1280, 720]

  # サムネイルの生成
  #100×100のサムネイルの生成
  version :thumb do
    process reseze_to_fill => [100, 100]
  end

このアップロードされたものをトップ画面に表示したい。

app/views/top.html.erb
<%= render "header" %>
<%= @store.each do |store| %>
  <%= image_tag store.images[0].url %>
<% end %>
<%= render "footer" %>

この前にもちろん、インスタンス変数の@storeにアップロードされた画像を渡す必要がある。

app/controllers.html.erb/homes_controller.erb
class HomesController < ApplicationController
  def top
    @store = Store.all
  end
  #中略
end

なぜかサムネイル表示できない。。。。。。
⬇︎
サムネイルの動作が働くのは新たにアップロードをした時なので、この機能を追加する前に動作が働かないのは当然。
よって、この機能を追加して再度一からやり直してみようと思った。
しかし、色々できない。。。。。。。。。。。

binding.pryとかで色々どこでエラーが出てるかもわかるらしいし、rubyの勉強がきちんとできていないと思うからパーフェクトrubyを一から読んでみる。

さらには、結局聞いて見たところ、
serialize :images, JSONでJSONに変更したところでSQLiteではJSONは受け付けていないから無理!!!

ということで色々直すの面倒なので、一から作り直す
+
複数アップロードの際にJSONを使うのではなく、モデルではbelongs_toとhas_manyの構造を使用する