#はじめに
開発しているメモアプリにランク付けをしていきたいと思います。
今回は三段階で評価していこうと思います。
それに伴い、星★による評価の入力・保存・表示について学習していきます。
参考
マイグレーションファイルにカラムを追加
notesテーブル(メモテーブル)のrateカラム(型:float)に評価値を保存する
すでに、テーブルとカラムは作成されていることを前提に進めます。
カラムは、半分の星による評価を行う場合、「0.5」や「1.5」という値を保存することになるため、float型にしておく必要があります。
もし、integerやstringの型として作成してしまっていた場合は、データベースによって変更方法は異なりますが、型の変更が必要になります。下記の記事でこの型の変更の沼にハマってしまった時の解決策を書いています。
class CreateNotes < ActiveRecord::Migration[5.2]
def change
create_table :notes do |t|
t.text :title
t.integer :user_id
t.integer :category_id
t.text :explanation
t.float :rate
t.timestamps
end
end
end
rails db:migrate:reset
javascriptの読み込み、★画像の読み込み
上記参考リンクを確認しながら、javascriptの読み込みと星の画像の読み込みを行います。
やり方(2種類)
①jQuery Ratyを使用するには、https://github.com/wbotelhos/raty からjquery.raty.jsをダウンロードする。
ダウンロードしたスクリプトをウェブサイトの任意の場所に配置する。
app/javascriptsのフォルダの中にダウンロードしたjquery.raty.jsファイルを配置する
②jQuery Ratyを使用するHTMLの中でJavaScriptを読み込む。RatyはjQueryのプラグインなので、jQueryのスクリプトも必要である。
<script src="/js/jquery.min.js"></script>
<script src="/js/jquery.raty.js"></script>
今回は①のやり方で実装していきます。
*ここでJavaScriptも定義していきます。
javascripts/application.js
ファイルに追加する
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery #追加
//= require jquery_ujs #追加
//= require_tree .
Gemファイル追加
gem 'jquery-rails'
budle install
モデルの記述(紐付け)
class Note < ApplicationRecord
# ユーザーとの紐付け
belongs_to :user,optional: true
# バリデーション
validates :title, presence: true
validates :explanation, presence: true
# カテゴリーと紐付け
belongs_to :category
validates :rate, presence: true
validates :rate, numericality: {
# only_integer: true,
less_than_or_equal_to: 3,
greater_than_or_equal_to: 1,
}
# numericality=空を許可する
numericalityは、デフォルトでは小数も許容してしまいます。rateカラムでは整数のみ許可したいので、 only_integerを。
例
validates :param3, :numericality => { :less_than_or_equal_to => 3}
# 数字が3以下であるか
validates :param3, :numericality => { :greater_than_or_equal_to => 1 }
# 数字が1以上であるか
end
#コントローラーの記述
class NotesController < ApplicationController
before_action :authenticate_user!
def new
@note = Note.new
end
def create
# @note = Note.new(note_params)
@note = current_user.notes.build(note_params)
@note.save
redirect_to notes_path
end
def index
# is_validがマッチするレコードを全て取得
@categorys = Category.where(is_valid: true)
@q = Note.all.ransack(params[:q])
@notes = @q.result(distinct: true)
end
def show
@note = Note.find(params[:id])
end
def edit
@note = Note.find(params[:id])
end
def update
@note = Note.find(params[:id])
@note.update(note_params)
redirect_to note_path
end
def destroy
@note = Note.find(params[:id])
@note.destroy
redirect_to notes_path
end
def search
@categorys = Category.where(is_valid: true)
@category = Category.find(params[:id])
@q = @category.notes.all.ransack(params[:q])
@notes = @q.result(distinct: true).page(params[:page])
@title = @category.name
render 'notes/index'
end
private
def note_params
params.require(:note).permit(:title, :category_id, :explanation,:user_id,:rate)
end
end
ここではnote_params
メソッドにrate
カラムを追加します。
メモ登録フォームを作る
<%= form_with model:note, local: true do |f| %>
<div class='form-group'>
<%= f.label :タイトル %>
<%= f.text_field :title, class: 'form-control', id: 'note_title' %>
</div>
<div class='form-group'>
<%= f.label :カテゴリー %>
<%= f.collection_select :category_id, Category.all, :id, :name %>
</div>
<!-- 評価 -->
<div class="form-group row" id="star">
<%= f.label :rate,'重要度 ', class:'col-md-1 col-form-label' %>
<%= f.hidden_field :rate, id: :review_star %>
</div>
<div class='form-group'>
<div id='editor'>
<%= f.label :内容 %>
<%= f.text_area :explanation, rows: 10, class: 'form-control', id: 'note_explanation', "v-model" => "input", name: "note[explanation]" %>
<h2><i class="fas fa-eye"></i> Preview</h2>
<div id="preview-field" v-html='input | marked'>
</div>
<div ></div>
</div>
<%= f.submit '登録', class: 'btn btn-success' %>
</div>
<% end %>
<!-- リアルタイムプレビュー -->
<script type="text/javascript">
window.onload = function() {
new Vue({
el: '#editor',
data: {
input: '<%== j @note.explanation %>',
},
filters: {
marked: marked,
},
});
};
<!-- 評価 -->
$('#star').raty({
size : 36,
starOff: '<%= asset_path('star-off.png') %>',
starOn : '<%= asset_path('star-on.png') %>',
starHalf: '<%= asset_path('star-half.png') %>',
scoreName: 'note[rate]',
half: true,
});
</script>
ポイントは下記
# ★の半分の入力ができるようにするため
half: true,
星による評価の表示
メモ一覧にて、★を表示したい。
上記の「★の入力、保存」と異なる点は、1.入力はせず表示する 、 2.繰り返し処理をするということになります
<div class='row'>
<table class='table'>
<thead>
<tr>
<th>タイトル</th>
<th>カテゴリー</th>
<th>重要度</th>
</tr>
</thead>
<tbody>
<% @notes.each do |note| %>
<% if user_signed_in? && current_user.id == note.user_id %>
<tr>
<td>
<%= link_to note_path(note) do %>
<%= note.title %>
<% end %>
</td>
<td><%= note.category.name %></td>
<!-- 評価 -->
<td>
<div id="star-rate-<%= note.id %>"></div>
<script>
// 繰り返し処理でもidをidを一意にできるようにnote_idを入れる
$('#star-rate-<%= note.id %>').raty({
size: 36,
starOff: '<%= asset_path('star-off.png') %>',
starOn : '<%= asset_path('star-on.png') %>',
starHalf: '<%= asset_path('star-half.png') %>',
half: true,
// 読み込みだけで入力できない
readOnly: true,
score: <%= note.rate %>,
});
</script>
</td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
</div>
ポイントは下記
# 繰り返し処理を実行してもidを一意に保てるようにreview.idを埋め込む
<div id="note-rate-<%= note.id %>"></div>
# 読み取り専用(入力できない)
readOnly: true,
# 星の入力値を読み込む
score: <%= note.rate %>,
これで完成!
#最後に
説明が分かりづらかったりすると思いますがご了承ください。
また、間違っているところがあればご教授いただけると幸いです。