少しまがあきました
以前の続きを
目次
1,モデルを作成する
2,ルーティングを設定する
3,該当するアクションをコントローラに定義する
4,メッセージ送信機能を実装する
5,グループにメッセージを表示する
6,サイドバーに最新のメッセージを表示する
7,細かいリンクの作成
1,モデルを作成する
$ rails g model message
class CreateMessages < ActiveRecord::Migration[5.2]
def change
create_table :messages do |t|
t.string :content
t.string :image
t.references :group, foreign_key: true
t.references :user, foreign_key: true
t.timestamps
end
end
end
$ rails db:migrate
アソシエーションの定義
class Message < ApplicationRecord
belongs_to :group
belongs_to :user
validates :content, presence: true, unless: :image?
end
前半のvalidates :content, presence: trueは
contentカラムが空の場合は保存しない、というバリデーションです。
後半で、unless: :image?という条件を追加しています。
unlessはifの逆の役割があります。if: :image?であれば
imageカラムが空でなければという意味になりますので
unless: :image?はimageカラムが空だったらという意味です。
class Group < ApplicationRecord
# 〜省略〜
has_many :messages
end
class User < ApplicationRecord
# 〜省略〜
has_many :messages
end
2,ルーティングを設定する
Rails.application.routes.draw do
devise_for :users
root 'groups#index'
resources :users, only: [:edit, :update]
# 以下のgroupsとメッセージをネストして作成
resources :groups, only: [:new, :create, :edit, :update] do
resources :messages, only: [:index, :create]
end
end
3. 該当するアクションをコントローラに定義する
2で設定したルーティングで必要なアクションをコントローラに定義します。
4,メッセージ送信機能を実装する
CarrierWave導入
機能の一つとして
画像の送信には、CarrierWaveというgemを使用します。
まず導入から記載して行きます。
$ brew install imagemagick
# 〜省略〜
gem 'carrierwave'
gem 'mini_magick'
$ bundle install
railsでuploader image追加
$ rails g uploader image
rails g uploader imageコマンドを実行すると
app/uploadersディレクトリ以下にimage_uploader.rbが作成されます。
# 〜省略〜
mount_uploader :image, ImageUploader
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick # ①ここのコメントアウトを外してください。
# storage :fog
# 〜省略〜
process resize_to_fit: [800, 800] # ②任意の箇所に追記してください
# resize_to_fitは縦横比を維持したまま、縦横を800px以内にリサイズするという意味です。
# 〜省略〜
end
メッセージ送信機能を実装
class MessagesController < ApplicationController
before_action :set_group #①事前動作の設定
def index
@message = Message.new
@messages = @group.messages.includes(:user)# 「n+1問題」を避けるために、includes(:user)の記述を忘れずに行いましょう。
end
def create #②createアクションの定義
@message = @group.messages.new(message_params)
if @message.save
redirect_to group_messages_path(@group), notice: 'メッセージが送信されました'
else
@messages = @group.messages.includes(:user)
flash.now[:alert] = 'メッセージを入力してください。'
render :index
end
end
private
def message_params
params.require(:message).permit(:content, :image).merge(user_id: current_user.id)
end
def set_group #③ストロングパラメーターに設定
@group = Group.find(params[:group_id])
end
end
# 〜省略〜
.form
= form_for [@group, @message] do |f|
= f.text_field :content, class: 'form__message', placeholder: 'type a message'
.form__mask
= f.label :image, class: 'form__mask__image' do
= icon('fas', 'image', class: 'icon')
= f.file_field :image, class: 'hidden'
= f.submit 'Send', class: 'form__submit'
.wrapper
= render "shared/side_bar"
= render "main_chat"
5,グループにメッセージを表示する
.messages
= render @messages
.message
.upper-message
.upper-message__user-name
= message.user.name
.upper-message__date
= message.created_at.strftime("%Y年%m月%d日 %H時%M分")
.lower-message
- if message.content.present?
%p.lower-message__content
= message.content
= image_tag message.image.url, class: 'lower-message__image' if message.image.present?
.side-bar
.header
%h3.header__name
= current_user.name
%ul.header__lists
%li.list
= link_to new_group_path do
= icon('fas', 'edit', class: 'icon')
%li.list
= link_to edit_user_path(current_user) do
= icon('fas', 'cog', class: 'icon')
.groups
- current_user.groups.each do |group|
.group
= link_to group_messages_path(group) do
.group__name
= group.name
.group__message
メッセージはまだありません
他の呼び出し方
上記では、render @messagesという記述で部分テンプレートを呼び出しています。
これは、以下のコードを省略した書き方です。
インスタンス変数の名前を単数形にしたものと
部分テンプレートの名前が同じならこのような省略をすることができます。
.messages
= render partial: 'message', collection: @messages
下もありますが遅いのでやりませんでした。
.messages
- @messages.each do |message|
= render partial: "message", locals: { message: message }
6. サイドバーに最新のメッセージを表示する
class Group < ApplicationRecord
has_many :group_users
has_many :messages
has_many :users, through: :group_users
validates :name, presence: true
# 下記のshow_last_messageを追加
def show_last_message
if (last_message = messages.last).present?
last_message.content? ? last_message.content : '画像が投稿されています' # 三項演算子 参照
else
'まだメッセージはありません。'
end
end
end
.side-bar
.header
%h3.header__name
= current_user.name
%ul.header__lists
%li.list
= link_to new_group_path do
= icon('fas', 'edit', class: 'icon')
%li.list
= link_to edit_user_path(current_user) do
= icon('fas', 'cog', class: 'icon')
.groups
- current_user.groups.each do |group|
.group
= link_to group_messages_path(group) do
.group__name
= group.name
.group__message
= group.show_last_message # ここを追加してmodelの内容を引っ張って来る
三項演算子
show_last_messageの内容で使用
初めに条件式を記述し、その後にtrueの時の値、続いてfalseの時の値を取ります。
1行で場合分けを行えるので、記述を短くまとめたい際に重宝します。
# 三項演算子の書き方
条件式 ? trueの時の値 : falseの時の値
ifを用いて書き直すと、以下のようになります。
def show_last_message
if (last_message = messages.last).present?
if last_message.content?
last_message.content
else
'画像が投稿されています'
end
else
'まだメッセージはありません。'
end
7.細かいリンクの作成
以下の3点をそれぞれ設定して終わりです。