はじめに
自分で作成しているアプリに、お知らせ機能を追加したが各マイページのお知らせアイコンの横に、未読のものがあればメール画像の上に印(点)をつけ、全て既読しているのであれば印はつけないようにするということをしたい。
※userとnewsについてのモデルは作成済み。
流れ
- clickというモデルを作成、user_idとnews_idを外部キーとする。
- 各ユーザがニュースをクリックしたら、dbに保存される。
- dbがnilだったらdbに保存されて、nilではなかったら保存されない(一番古い情報(クリック時間)のみ保存)。
- nilがあればマイページトップページに印がつき、且つ、各ニュース一覧の該当するnilのnewsに「new」がつく。
db作成
まずはクリックしたかどうかのテーブルを作成する。
①今回はclickというテーブルを作成。
$ rails g model click
② userとnewsを外部キーとして設定
③message_show.html.erbに各newsの内容を表示するファイル作成。
④wants_controller.rb
にまだクリックしたことがないnewsをクリックするとdbに時間とnews_idとuser_idが保存されるコード記述。
def message_show @message = News.find(params[:news_id]) already_clicked = Click.find_by(news_id: params[:news_id], user_id: current_user.id) if already_clicked.nil? Click.create!( clicked: params[:created], user_id: current_user.id, news_id: params[:news_id] ) end render "message_show" end
これで何回クリックしても、古い情報のみ保存され、新しい情報は保存されないコード完成。
お知らせ一覧ページ(news一覧)に未読であれば[new]をつける
①wants_controller.rb
にクリックの情報がnilかどうか確認のためのインスタンス変数作成。
def message @messages = News.all @already_clicked = Click.find_by(news_id: params[:news_id], user_id: current_user.id) render "message" end
②includeを使ってjoinする(newsのテーブルと、clickのテーブルをつなぐ)
where(clicks: {user_id: [current_user,nil]})
でclickテーブルの中の、user_id。arrayで[current_user,nil]
で、current_userか(or)nilということになる(全ニュースを表示したいのでこのようにした)
def message @messages = News.includes(:clicks).where(clicks: {user_id: [current_user,nil]}) render "message" end
h1>お知らせ</h1> <ul> <% @messages.each do |message| %> <li> <% if message.clicks.empty? %> <small>new</small> <% end %> <%= link_to message.title, message_path(message) %> </li> <% end %> </ul>
empty?
はarrayの結果が[](空)の場合の判断(nilではない)。
これでnewの表示完了。と思ったが、他のユーザがクリックしたnewsが表示されないエラーあり。
もう一度仕切り直し、message.current_user_clicked
というふうにcurrent_user_clicked
というメソッドの中にcurrent_userが入れられたらいいなぁ。
ということでcurrent_user_clicked
というメソッドを作成する。
①app/models/news.rb
を編集しcurrent_user_clicked`というメソッドを作成する。
class News < ApplicationRecord has_many :clicks def current_user_clicked(current_user) Click.find_by(news_id: id, user_id: current_user.id) #current_userはerbから引数として渡さないと使用できないため引数設定 end end
②app/views/wants/message.html.erb
も編集。
<h1>お知らせ</h1> <ul> <% @messages.each do |message| %> <li> <% if message.current_user_clicked(current_user).nil? %> <small>new</small> <% end %> <%= link_to message.title, message_path(message) %> </li> <% end %> </ul>
これでcurrent_userが読んでいないニュースに関してはnewマークがつくようになった。
トップページのメールアイコンの未読通知印の実装
前回作成したnews.rb内のメソッドを今回も使用。 ①erbの編集
<header> <div><h1><span class="logo-jp">むだゼロ</span><br>muda0</h1></div> <div class="flex_menu"> <div class="layer"> <%= link_to(messages_path) do %> <%= image_tag 'mailicon.png' %> <% @messages.each do |message|%> <% if message.current_user_clicked(current_user).nil? %> <p>●</p> <% end %> <% end %> <% end %> </div> <div><%= link_to "欲しいものを登録", wants_new_path, class: "new_button" %></div> <div><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></div> </div> </header>
②wants/controller
は@messages = News.all
のみ記述。