Open tatsuki-okuda opened 3 years ago
一旦投稿してみてエラーないかのログを確認する。
https://gist.github.com/tatsuki-okuda/ec461af5dbe5040d296c382c76388a9e
Unpermitted parameter: :imgs
とあるので、ストロングパラメータで弾かれている。
ストロングパラメータの指定と、 モデルの紐付き名の指定、 formでの指定を確認する。
どれも同じ :imgs で定義してある。
となると、
・formからの渡し方に問題があるか
・paramsの渡し方が違う
になる。
formからの渡し方としてはinputで渡している。 これ以外にファイルの渡し方はないので、問題はなさそう。 inoutのfileにおいても複数選択できるようにオプションもつけているが、 指定の仕方の違いがあるかもしれない。
現状は
:multiple => true
になっているので調べてみる
multiple: true
と定義しているものもある。
試しに変えてみたらシンタックスエラーになったので
元々のやつであってそう。
となるとこちらの仮説は間違っている。
これに関しては、元々の処理が保存されるので :imgsの部分で違うのかもしれない。 ファイルが一枚だけだった時(アバターの登録時)は同じ指定で通ったので、 ファイルが複数枚になっていることに何か関係がありそう。
エラー分でググってみると以下の記事を見つけた unpermitted parametersのエラーでちょっとだけはまった話
どうやら、配列でわたてくるときはそれも指定するみたい。
ストロングパラメータの配列に関して調べてみた Rails5 Strong Parametersで複数の配列を許可する
これだ Railsガイド 4.5 Strong Parameters
なので、ストロングパラメータで配列を指定すれば処理が通りそう。 has_many_attachedの場合は何か特殊なルールに基づいた配列への格納があるのかも調べてみたら Active Storageで複数ファイル添付 でも詳細に書かれていた。
あとmultipleの指定が僕と違うので、気になるので、
再度変更してみた。
= f.file_field :imgs,multiple: true, class: 'imgs'
でシンタックスエラーなくできた笑
以上の2点を踏まえて再度トライ!
無事に保存ができた! https://gist.github.com/tatsuki-okuda/82a92f88fa45058abcc08826fd28b1ca
DBを確認しても同じ時間に3枚の画像が保存されているのがわかる。 https://gist.github.com/tatsuki-okuda/726db1d7dd0cac960c1994317b8a1d1a
以上を確認できたので、 画像の保存のアクションは完了!!
・投稿が完了した時の遷移先がcards_pathになっているので、 ここをroot_pathに変更してrootに飛ばす。
・投稿のアバターのimgがデフォルトのままだったので、 登録しているアバターで表示できるように切り替え。
**2. newではなくeditで新規投稿ができるようにしてupdateで処理をする**
3. APIを用いた非同期での処理にする
4. 投稿した画像をスライドで表示させる
5. 画像を選択したときはプレビューで表示する
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
これに関してはわざわざeditを使ったややこしいやり方をするのではなくて、 テンプレを使い回す方でいく。
そのほうがシンプルでrailsの書き方にそう。
フォームをテンプレ化させる。
動作の確認
問題なく動作した。
3. APIを用いた非同期での処理にする
4. 投稿した画像をスライドで表示させる
5. 画像を選択したときはプレビューで表示する
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
・formを用いたAPIの設定を調べる
・JSファイルの作成
・フォームの送信のコントロール、axiosでリクエストとレスポンスの管理、params設定
・axiosでコントローラーにリクエスト遅れているかのログチェック
・ストロングパラメータ通るかのチェック
・cardコントローラでjsonを返す処理への書き換え
・jsonの作成(serializerは画像データとかどう扱うのか?、json用のurl発行も,なければavatarと同じように)
・jsonの確認
・JSでデータをviewに表示させる。
・パスに入って来た時の一覧表示のリクエスト作成
・jsで表示できるようにメソッド作成
・indexアクションのjson作成
・コンソールをみながらレスポンスの確認
・データ表示の確認
参考になりそうなのと、ajaxについて調べたものはこちらにまとめた。 RailsにおけるFormの非同期処理(Ajax)
調べてみてわかったけれども、 formを用いた非同期の場合は今まで同期通信でページを入れ替えていた部分(最終的にhtmlファイルが返ってくる) でjs.haml形式のファイルが帰ることになる。
そのため、今まではコントローラーで処理が完了した後にリダイレクトしていた部分が使えなくなり、 (リダイレクトが同期的な処理)代わりにこのjs .hamlを読み込み、そこでJSが実行されて、 htmlを書き換える処理をする流れになる。
なので、元々のhamlを書くときにブロックごとに細かに区切って、 テンプレを用意していき、それをrenderで読み込ませる感じになる。 js.hamlの実行で書き換える場所を指定して、そこにテンプレを投げ込むような形で ページが切り替わるということになる。
フォームでの流れとなると
現在のページへアクセス(同期or非同期)
↓
フォームが送信(ajax)
↓
対象のコントローラーで対象となるメソッドが処理される
↓
コントローラーで必要なものはインスタンス変数として渡す
↓
コントローラーがjs形式のレスポンスを返す(js.haml,)
(同期通信ならhtml.hamlを返す)
↓
js.hamlのjsが処理されて、現在のページが描き変わる
ということになる。
今回の新規投稿であれば、
indexでカメラマーク(投稿btn)をタップ
↓
newページに遷移する
↓
投稿内容入力
↓
submitでリクエスト
↓
コントローラーで処理
↓
レスポンスとしてリダイレクトでindexに戻す
というフローになる。 非同期でhtmlを書き換えることを考慮すると、
indexでカメラbtnをクリックした時のlink_toも非同期で処理をして、
indexのページを書き換えて、フォームを表示させる
(link_toでページを切り替えるとフォームを送信した時にリダイレクトできないので、
rootのURL(indexページ)に戻れなくなってしまうため)
↓
フォームの送信を非同期で行う
↓
コントローラーで処理、レスポンスとしてjs.hamlを返す
↓
js.hamlで表示していたフォームを元のindexに書き換える。
(保存されたデータはコントローラからインスタンス変数で渡すので、
投稿した新い投稿も表示される)
というフローになると考えられる。
これに関しては変更を加えるところが多くなるので、 一旦は投稿のフローを同期通信で実装してから、 必要なところを切り替えて非同期で処理できるようする。
現状ではまだ、投稿の保存は確認できるが、 画像の表示はまだ完璧に実装できていないため、 中途半端な段階と言える。 この状態で非同期のような処理に切り替えると、 話がややこしくなるためである。 (非同期を実装しながら、画像の表示も実装することになる)
4. 投稿した画像をスライドで表示させる
5. 画像を選択したときはプレビューで表示する
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
【保留】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
保存まで確認できているので、 投稿したものに対して、一覧で表示させるフロー
・現状は1枚だけ表示できるが、スライド形式で投稿した画像を全て表示できるようにする。 ・画像はリサイズして、縦横のアスペクト比を固定にする。
現状の1枚だけの表示を複数枚で表示できるようにする
→データは配列で渡ってくるので、それを抜き出す
→viewでforeachで書き出す
まずはデータ確認 rails cでimgのデータは配列で渡っているのかを確認。
↓確認ログ https://gist.github.com/tatsuki-okuda/3400706346e03106625b5a0d159f3998
であればimgsをeach分で書き出せば問題はなし! 実際にやってみるとちゃんと全ての画像が表示された!
保存時に色々といじるのもあれなので、 簡単にできるようにcssのobjectfitで代用。
必要あればスライド入れた時に変更する
【完了タスク】
2. newではなくeditで新規投稿ができるようにしてupdateで処理をする
4. 投稿した画像をスライドで表示させる
→表示まで
【next】
4. 投稿した画像をスライドで表示させる
→スライドシュー導入
5. 画像を選択したときはプレビューで表示する
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
【保留】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
【next】
4. 投稿した画像をスライドで表示させる
→スライドシュー導入
5. 画像を選択したときはプレビューで表示する
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
【保留】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
今回はswiper.jsを使ってスライドを実装する。
なので、swiperの読み込みとjsファイルの作成とhtmlの書き換えが必要
必要ファイルの読み込みはこちらから [Rails]Swiperで画像スライド作成
swiperのデザインはこちらを参考にした サンプル付き!簡単にスライドを作れるライブラリSwiper.js超解説(基礎編)
特に問題はなく読み込みと実装が完了!
5. 画像を選択したときはプレビューで表示する
【next】
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
【保留】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
・inputファイルをアップロードした時に読み取る
・読み取ったデータは配列のはずなのでjsで展開する
・viewでの表示はスライドショーにしたいので、appendで入れる
・スライドはswiperを使う
順番
1:スライドはswiperを使う
2:viewでの表示はスライドショーにしたいので、appendで入れる
3:inputファイルをアップロードした時に読み取る
4:読み取ったデータは配列のはずなのでjsで展開する
こちらはindexでの表示で使用しているのでそちらを使う
まずはファイルをアップロードした時に表示されるviewの部分を作っておく。 appendで入れるのは最後の確認とする
こちらに関しては以前のアバターで参考にした
Railsのfile_fieldで画像クリックでアップロードしてプレビューを差し替える
をベースとしてやる。
問題になりそうなのが、 単数ではなくて複数の時にどうなるかだ。
読み取ったファイルデータはfilesで読み取れて、そこに配列として格納されている。 なので、ここに対して、for分で一個ずつ取り出して、アップロードの処理を加える。
結果としては、画像のアップロードでプレビュー表示はできたけれども、 スライドできないのと、コンソールに以下のエラーログが出力された。 https://gist.github.com/tatsuki-okuda/3376c81195f42b8ce5e4316110b11b39
formPreview.js:16 Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
タオポエラーでfilereaderのreadAsDataURLのパラメータの一つがblobではないとある。
今、パラメータでわたているのはfilesから抜き出した要素なので、その中の一つがblobではないということになる。
for文で渡しているのは const file = uploadFiles[i];
でここの一つがblobではないということになる。
何か指定が間違えているのかと思ったら、for文で
for(i= 0; i <= uploadFiles.length; i++){
とあり、0番目から始まっているのに対して、 i <= uploadFiles.length
となっている。
おそらくここで、中身のない配列の要素が渡ってしまっているので、
for(i= 0; i < uploadFiles.length; i++){
に変更したところ、エラーは無くなった。
しかし、 問題点としてはswiperがちゃんと動いていない。
今はfor分の中でfileのonloadが実行されて、かつ、最後の時にしてある。 これはswiperがdomを読み込んだ後に実行しないと要素がないまま実行されたら、 swiperが機能しないからである。
なので、for文でimgタグに全ての画像をセットしてから実行する必要がある。
この時の条件は
if( i === uploadFiles.length){
とあるが、先ほど、変更したfor分の条件で行くとi < uploadFiles.length
までしか
処理は繰り返されないので、この条件が一致しないことになる。
となると最後の番号の一つ前で実行する必要があるので、条件を以下のように書き換える。
if( i === (uploadFiles.length - 1)){
これで一回動くか確認数する。
結果は動かなかった。。
もしかするとsweiperでの指定の違いかもしれない。 swiperの場合はslideはswiper-wrapperに入れる必要があるが、 今のhtmlではswiper-slideにappendしている。
これを直す必要がある。
なので、
divを生成してそこにswiper-sildeのクラスをつける
imgタグを生成してそこにimgのsrcをセットする
divの子要素にimgを入れる。
swiper-wrapperの要素を取得する
そこにdivを子要素として入れる。
この順番に直してhtmlを確認したら 問題なく、イメージした構成を作れた。
しかし、swioperはいまだに動いていなかったので、if分の条件を if( i === uploadFiles.length){ に戻したところ、slideで表示されるようになった。
最後にcssを整えて完成!!!
【追記】
記事を探していたら枚数制限のものがあったので、 ついでに10枚を限度にするのを付け加えておく。 [JS][Rails]プレビュー付き画像アップロードで画像枚数に制限をかけよう!!
【参考】
【next】
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
【保留】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
【next】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
・投稿のデータから投稿した日付を抜き出す
・railsの中で日本時間で現在の日付を設定する
・現在の日付と投稿した日付の差から投稿が何日前なのかを表示させる
・投稿者の名前と画像を引っ張ってくる
1:投稿者の名前と画像を引っ張ってくる
2:投稿のデータから投稿した日付を抜き出す
3:railsの中で日本時間で現在の日付を設定する
4:現在の日付と投稿した日付の差から投稿が何日前なのかを表示させる
こちらはuserとcardが紐づいているので 直接viewで呼び出す。
card.user.username
投稿データは create_atで取得できる。 時間の設定が変なので日本時間に変更させる。
config > application.rbで
config.time_zone = 'Tokyo'
を記述して日本z間に合わせる。
【Rails】created_at、updated_atを日本時間に変更して良い感じに表示する方法
create_atと現在時刻からの差分を求める。 まずは調べてみる。
どうやらtime.zone.nowとの差分で求められる。
Railsタイムゾーンまとめ こちらの記事でもtime.zone.nowが推奨されているとあるので、 これで良さそう。
こちらの記事で年単位でも取得できることがわかる https://qiita.com/ogin_s57/items/0fe7f7695b7a9d9b4b21
こちらはcardのモデルに書いて、viewでメソッドとして使えそう。
distance_of_time_in_words_to_now
がうまく機能していない(投稿してからの日が1kヶ月以上ないと0が返ってくるので)
その場合の時はif文で日にちか時間を表示させてあげたら良さそう。
具体的には0で帰るときは空文字でメソッドを返すように改良して、 その時に合わせてviewでif文を書くことで、投稿して1ヶ月に満たないものは日にちで、 それにも満たないものは時間で表示することができた。
しかし、 投稿した時の日付がおかしいのか、昨日に投稿した投稿が18daysagoとなっていたりするので、 日にち換算の方でおかしくなっている。。
time.zoneとcreate_atで時間の基準がズレているっぽいので、 これに関してはひとまずOKにして、 後日、DBのデータの時間の基準も調べてみることにする。
【next】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
【追加】
7, snsシェアボタンの追加
8, 投稿した時間のズレの修正
工程として2つ追加する。
7, snsシェアボタンの追加
【next】
3. APIを用いた非同期での処理にする
→4,5,6が終わった後で処理を切り替える
【追加】
8, 投稿した時間のズレの修正
先にSNSのシェアボタンを作る。 apiに関しては一旦置いといて、 投稿の昨日としていいねとフォローを実装してからにする。
twitterでのシェアを実装する。 シェアをするにはtiwtterのAPIを使用する必要がある。
先に調べてみると、
と言う記事があったので、 こちらを参考にできそう。
とりあえず、linkを作ってみるが 問題点がある。
・その投稿へのurlはどのようにして発行するのか? ・画像データはシェアできるか?
この2点だ。
Railsにおけるurlの取得はrequest.urlで取得できるみたいだ。
これで、一旦URLがどのように発行されるかをみてみると、
http://localhost:3000/
indexのurlが発行された。
今、欲しいのは投稿毎のidが乗ったurlだ。
となると、 showページへのパスを用意して、 それをふづいさせれば行けそう。
card_pathでurlを取れるので、 文字列連結でurlを作成すればいけそう。
http://localhost:3000//cards/1
urlは作れたが/がダブってるので、 普通にヘルパーを使わずに文字列を連結させて、
= link_to "https://twitter.com/share?url=#{ request.url }cards/#{card.id}&text=#{ card.content }", class: 'btn btn-default', target: '_blank' do
これで完成!
http://localhost:3000/cards/1
あとはshowページを作るだけなので一旦完成!
twitterへのシェアボタンをアイコンにしたいので 【Rails】Font Awesomeの使い方 を参考にFont Awesomeを導入!
hamlの場合は少し手順を踏むみたいなので、
記事にあると通りにやってみると、
undefined method
icon' for #<#
一応、何か設定の仕方を間違えているかもしれないので、 他の記事も探してみる。
FontAwesomeをhamlに導入する際に詰まったお話 こちらの記事が参考になりそうだったので、みてみると、 設定方法は同じだった。。。
となると、rails serverを再起動したら 反映されるパターンかもしれないので、再起動。
すると問題なく動作した!!
bundle等を入れた時は設定が反映されないことも多いので、 こまめにサーバーを再起動するようにしよう。
showページを作成したので、そこへ飛ぶリンクをindexの投稿に追加。 またshowページがちゃんと表示されるを調整しておいた。
titterカードのメタタグ等の設定で実装できそうな感じはある。
Twitterカードを設定してみた(感謝を言葉にする! 2回目)
こちらの記事によるとURLをツイートしたり、投稿したりしたときに出てくる カードの設定をメタタグを使ってできるという。
であれば、 カード毎の情報を引き出せるようにして記載すれば、 投稿にと言うよりはカードの中で画像の表示が可能になる?
メタタグで調べていたところ、以下のgemで簡単に作成できそう https://github.com/kpumuk/meta-tags#twitter-cards
【Rails】『meta-tags』gemを使ってSEO対策をおこなう方法 こちらも参考にして、
・metaタグの初期設定をおこなうため、「app/helpers/application_helper.rb」にdefault_meta_tagsメソッドを実装する。
・それをview「app/views/layouts/application.html.erb」でgemのメソッドを使って表示させる
と言う流れみたい。
なのでヘルパーにmetaタグの詳細を記述して (https://gist.github.com/tatsuki-okuda/e15dd3671f3e138cdfd02dcea71e4671) viewで表示させると
undefined method
with_indifferent_access' for #
エラー分で調べてみると https://stackoverflow.com/questions/47114258/undefined-method-with-indifferent-access-for-array でハッシュではなくて配列が渡っていることが理由らしい。
Railsで with_indifferent_access を使うときは一呼吸おいて考えて欲しい
一旦、default_meta_tagsで何が返っているかを確認すると、 確かいに配列が返っている。 その配列の中にハッシュが格納されていると言うことか。 https://gist.github.com/tatsuki-okuda/990f83f46792ebd00dd4f971b7fc019d
であれば、ここでの配列の返りを直せばうまくいく?
ループを使うと配列で出てしまうので、 そこの実装を変更して、画像の0番目だけを表示できるようにする。
headにはif分でcard_pathのときにカードを表示できるようにしたいが、 今、idがないとエラーになってしまうので、 インスタンス変数として@cardがあって、かつcard_pathのときに条件をつけるとうまくいく。
これでshowページだけの時にカードが表示できた。
【追記】
urlの生成を調べていたときに以下の記事で urlの取得の中でリクエスト元にurlの取得があった。 RailsでのURLの取得
ヘッダーの戻るの矢印で一つ前のページに戻れるようにしたかったので、 こちらからリクエスト元のurlをしてしてあげれば前にいたページに戻れる。
なので、実装しておく。
【追記2】
APIで調べていたときに面白そうなのも発見したので、 書いておく。
【残】
3. APIを用いた非同期での処理にする
8, 投稿した時間のズレの修正
apiに関しては人とりに実装(いいねとかフォロー)を 実装してから変更する。
【ゴール】
新規投稿で、テキストと複数枚の画像を投稿できる
機能
画面の写真のアイコンをタップで新規登録画面 テキスト入力と、複数枚の画像の選択 選択された画像はプレビューで表示する。 投稿のボタンをクリックで保存する。
対象となるモデル
card, user
DBの紐付き
userモデルに対して外部キーでcardモデルが紐づいている。 userモデルはcardモデルを複数所持する1対多の関係。
モデルの紐付け
userモデルにcardモデルが紐づいている。
cardモデルに対して
has_many_attached :imgs
で複数枚の画像を紐づかせる。また、cardモデルは
belongs_to :user
でuserに所属する。現状
・画面のアイコンをタップで新規投稿画面へ遷移 →こちらはcardのnewで実装している。
・そこにformがあり、テキスト入力と画像を選択できる。
・cardコントローラーのnewでbuildをして、 createでsaveしている。
・投稿をした時に投稿が表示されるので、newからcreateの処理は通っている しかし、画像の保存確認は取れていない
・表示された新規投稿の画像はデフォルトで設定しているもの。
・投稿の時に画像のプレビューがない
やりたいこと
・既存の処理の中で画像が保存されているのかの確認 APIを用いた非同期での処理にする →既存で書いている処理を書き換える必要がある。 ・画像を選択したときはプレビューで表示する。 ・投稿した画像をスライドで表示させる。 ・投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示) →ゆくゆくは誰がいいねしたみたいな情報があれば面白い ・newではなくeditで新規投稿ができるようにしてupdateで処理をする →後の編集でもeditを使いまわして、投稿がなければ新規、あれば編集と分岐させたい
順位付
投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
各工程の詳細
1. 既存の処理の中で画像が保存されているのかの確認
ログとデータベースでの確認。
2. newではなくeditで新規投稿ができるようにしてupdateで処理をする
ルーティングの変更 viewファイルの変更 コントローラーの変更
3. APIを用いた非同期での処理にする
jsファイルの作成と読み込み(editで) json用のurlの発行(ルーティングの変更も) formの非同期処理を調べる axiosの設定を調べる siniaraizerの作成でモデルデータをjsonで扱いやすくる
4. 投稿した画像をスライドで表示させる
jsonデータの変更 シンプルなスライドショーの追加。
5. 画像を選択したときはプレビューで表示する
uploadの読み込みでプレビューを表示させる。 いらないものは消せるようにするにはどうするかを調べる プレビューに表示するときのリサイズを調べる
6. 投稿から投稿者の情報、投稿時間を取得して表示させる(一旦は投稿時間と投稿者、投稿が何日前なのかを表示)
投稿の日時のデータの取得の仕方 その日時から、現在時刻の計算方法とその表示。