フレームワーク

Ratyの使い方|v4でjQuery記法が失効した星評価プラグインの導入とRails実装

Ratyの使い方|v4でjQuery記法が失効した星評価プラグインの導入とRails実装

この記事で扱うRatyは、divひとつを星評価のUIに変えるJavaScriptプラグイン(npmパッケージ名はraty-js)です。日本語の解説記事は$('#element').raty({ score: 3 })というjQuery記法で書かれたものがほとんどですが、この書き方はもう動きません。2022年10月2日公開のv4.0.0でjQuery依存そのものが取り除かれ、起動構文がnew Raty(element, options)に変わったためです。

やっかいなのは、古い記事の手順どおりnpm install raty-jsを実行すると最新の4.3.0が入る点です。インストールは成功し、ファイルも配置され、それでも星は出ません。原因がバージョン差にあると気づきにくい構図になっています。

以下は、公式changelogとUPGRADE.md、およびraty-js 4.3.0のソースを根拠に、旧記法からの移行点、画像版とフォント版のファイル配置、初期化で生成されるDOM、Rails 8での保存と表示までを順に整理したものです。

まとめ

先に結論だけ並べます。根拠は各セクションで扱います。

論点 結論(raty-js 4.3.0基準)
起動 new Raty(el, options) を作り init() を呼ぶ
jQuery記法の最終版 raty-js 3.1.1。v4系には $.fn.raty が無い
公式npmパッケージ raty-js。raty は無関係な別物
設定の優先順位 要素の data-* がJSのオプションに勝つ
最終リリース 4.3.0 / 2024-04-28(2026-08-05時点で更新なし)

既存プロジェクトがv2系のまま止まっているなら、移行は書き換えというより置き換えに近い規模になります。まずどこが失効したのかを押さえます。

v4.0.0で失効したjQuery記法と新旧オプションの対応

Ratyのバージョンは3世代に分かれます。v2系までがjQueryプラグイン、v3系がjQuery依存を残したままの内部リファクタリング、v4系が純粋なJavaScriptクラスです。世代をまたぐと動かなくなるのは、破壊的変更が2回入っているからです。

jQuery記法が動かない直接の原因

公式changelogのv4.0.0には「The jQuery dependency was dropped, so the syntax to start Raty was changed」と明記されています。v4系のsrc/raty.jsはclass Ratyを定義してexport default Ratyするだけの構造で、jQuery.fnへの登録処理を持ちません。$.fn.ratyが生えないため、$('#element').raty(...)はis not a functionで止まります。

さらにv4.2.0(2023-08-24)では、テストコードからもjQueryが取り除かれました。changelogの表現は「Drops jQuery from tests and so from the entire project」です。プロジェクト全体からjQueryが消えたという宣言なので、待っていても旧記法が復活することはありません。

なお、RatyがjQueryを手放したこととjQuery本体の動向は別の話です。jQuery自体は4.0系へ進んでおり、そちらの変更点はjQuery 4.0とは?新機能・変更点と3系からの移行ポイントを総まとめで扱っています。

書き換えが必要な5つの箇所

手を入れる箇所は次の表に集約できます。旧の書き方は世代で異なるため、v2系とv3系を分けています。

対象 v2系(3.0.0未満) v3系(3.1.1まで) v4.3.0
起動 $('[data-raty]').raty({}) 同左 new Raty(el, {}).init()
共通パス $.raty.path = 'assets' 同左 { path: 'assets' }
キャンセル { cancel: true } { cancelButton: true } 同左
関数呼び出し $('#el').raty('score') $('#el').data('raty').score() raty.score()
clickの引数 (score, evt) 同左 (score, element, evt)

このうち事故になりやすいのはcancelの改名です。v4に{ cancel: true }を渡してもエラーは出ません。defaultOptions()にcancelというキーが存在せず、渡された値がどこからも読まれないまま無視されるためです。キャンセルボタンだけが静かに消え、コンソールには何も出ません。

加えてv3.0.0ではdestroy・reload・setの3関数が削除されています。代替APIは用意されていないので、これらを呼んでいるコードはインスタンスを作り直す設計へ変える必要があります。

raty-js 4.3.0の導入手順とファイル配置

導入で最初につまずくのはパッケージ名です。npmでratyを引くと、koaベースのNode.jsフレームワークという無関係なパッケージが出てきます(1.0.5・2017-02-21公開)。星評価プラグインの公式パッケージはraty-jsで、リポジトリにgithub.com/wbotelhos/ratyが設定されています。

npm・CDN・3種類のビルドファイルの選び分け

インストール自体は1行です。

npm install raty-js

そのあと、どのファイルを読むかで書き方が変わります。4.3.0のpackage.jsonはmainにsrc/raty.js、typesにsrc/raty.d.tsを指定しています。src/raty.jsはexport default Ratyを持つES Modulesなので、バンドラやimportmap経由なら次の形で読み込めます。

import Raty from 'raty-js';

const raty = new Raty(document.querySelector('[data-raty]'), { score: 3 });

raty.init();

scriptタグで読む場合はbuild/配下です。ここで参照名が3通りに分かれます。build/raty.jsとbuild/raty.min.jsはクラス宣言を含む通常スクリプトなので、後続のスクリプトからRatyという名前で参照できます。ただしwindow.Ratyはundefinedのままです。クラス宣言はグローバルオブジェクトのプロパティにならないため、window.Ratyを前提にした遅延初期化コードは失敗します。

<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/raty.min.js"></script>

3つ目のUMD版(build/raty.umd.min.js)だけは形が違い、名前空間オブジェクトをglobalThis.ratyに置きます。このファイルでは素のRatyが未定義になり、クラス本体はwindow.raty.defaultから取ります。AMDやCommonJSと共存させる必要がなければ、raty.min.jsを選ぶ方が迷いません。

画像で星を出す場合に必要な5ファイルとpath指定

既定のstarTypeはimgで、星をPNG画像として描画します。npmパッケージのsrc/images/にはstar-on.png・star-off.png・star-half.png・cancel-on.png・cancel-off.pngの5枚が同梱されています。半星とキャンセルボタンを使わないなら前者2枚だけで動きます。

pathを省くと、生成されるimgタグのsrcはディレクトリを持たないstar-on.pngになります。ブラウザは現在のページURLからの相対で解決するため、/products/12のような階層下では404です。配信ディレクトリを明示してください。

new Raty(document.querySelector('[data-raty]'), {
  path: '/assets/raty',
  score: 3
}).init();

フォントアイコンで星を出す場合(starType: ‘i’)

画像を置きたくない場合はstarTypeにiを指定します。星はimgではなくi要素として生成され、star-on-png・star-off-pngといったクラス名が付きます。見た目はsrc/raty.cssのWebフォントが担当し、サイズはfont-size: 2emが既定です。

<link rel="stylesheet" href="/assets/raty/raty.css">

注意したいのがraty.cssの中身です。@font-faceのsrcが./fonts/raty.eotのような相対パスで書かれているため、CSSだけをコピーしてフォント一式を置き忘れると、星の位置に何も表示されないか豆腐文字が並びます。raty.cssと同じ階層にfonts/ディレクトリごと配置するのが確実です。

初期化で生成されるDOMと主要オプションの挙動

defaultOptions()が返すオプションは35個ありますが、実装で毎回触るのは一部です。使用頻度の高いものを既定値付きで並べます。

オプション 既定値 役割
score undefined 初期スコア
scoreName 'score' hidden fieldのname
number 5 星の数
numberMax 20 星の数の上限
path undefined アイコンの配信ディレクトリ
starType 'img' img か i
readOnly false 読み取り専用
noRatedMsg 'Not rated yet!' 未採点時のtooltip
half false 半星での投票
halfShow true 半星での表示
round { down: 0.25, full: 0.6, up: 0.76 } 半星の丸め境界
cancelButton false 取り消しボタン
hints ['bad', 'poor', 'regular', 'good', 'gorgeous'] 星ごとのtooltip
target undefined tooltipの表示先要素

残りの21個はアイコンの個別指定(starOn・starHalf等)とtarget系の細かい制御です。まずは上の14個で組み立てて、足りなければ公式tutorialを引く順序が早いです。

init()を呼ぶまで何も起きない構造

v4のコンストラクタはthis.elementとthis.optを代入するだけで、DOMには触れません。描画はinit()の中です。v2系の$(el).raty()が呼んだ瞬間に描画されたのと違い、init()を書き忘れるとdivは空のままになります。例外も出ないので、移行時に見落としやすい差分です。

init()を通すと、対象要素の中に星の要素と、スコアを保持するinput type="hidden"が生成されます。{ score: 3 }で初期化した場合、hidden fieldはname="score" value="3"です。フォーム送信時に評価値が飛ぶのはこのhidden fieldのおかげで、独自にinputを用意する必要はありません。

hidden fieldの名前を変えるscoreName

Railsのようにmodel[attribute]形式のパラメータ名が必要ならscoreNameを使います。

new Raty(document.querySelector('[data-raty]'), {
  scoreName: 'review[rating]',
  path: '/assets/raty'
}).init();

これでhidden fieldはname="review[rating]"になり、Strong Parametersのreviewスコープにそのまま乗ります。

読み取り専用表示に切り替えるreadOnly

投稿済みの評価を表示するだけならreadOnly: trueです。v4では星のイベントリスナーを外すのではなく、要素にpointer-events: noneを当てる実装に変わりました(changelog v4.0.0「The read only function now uses pointerEvents over unbind the listeners」)。同時にdata-read-only="true"が付き、hidden fieldにもreadonly属性が入ります。

スコア未設定のままreadOnlyにすると、全ての星のtooltipがNot rated yet!になります。日本語サイトではnoRatedMsgで差し替えてください。

new Raty(document.querySelector('[data-raty]'), {
  readOnly: true,
  noRatedMsg: 'まだ評価がありません',
  score: 4
}).init();

半星表示と丸めルール(half・halfShow・round)

平均評価のような小数値を扱うときは、表示用のhalfShowと投票用のhalfを混同しないでください。halfShowは既定で有効で、小数スコアを半星のアイコンとして描くだけの機能です。ユーザーに半星単位で投票させるならhalf: trueを別途指定します。

丸めの境界はroundで、既定値は{ down: 0.25, full: 0.6, up: 0.76 }です。公式tutorialの規定では、halfShowが有効なとき小数部が0.25以下で切り捨て、0.25超かつ0.76未満で半星、0.76以上で切り上げになります。halfShowを無効にするとfull(0.6)だけが参照され、0.6未満は切り捨て、0.6以上は切り上げの2値判定に変わります。

丸められるのはアイコンの見た目だけです。hidden fieldに入る値は小数のままで、{ half: true, score: 2.5 }ならvalue="2.5"が送信されます。平均値を保存している場合でも表示と保存値がずれません。

インスタンス経由で呼ぶ5つの関数

v4では関数をインスタンスから呼びます。変数に受けておかないと後から操作できないので、動的に触る予定があるなら必ず保持してください。

const raty = new Raty(document.querySelector('[data-raty]'), {});

raty.init();

raty.score(2);          // スコアを設定
raty.score();           // 現在のスコアを取得(2が返る)
raty.click(4);          // 4番目の星をクリックしたことにする
raty.move(3.5);         // 3.5の位置へマウス移動を再現
raty.cancel(true);      // 評価を取り消す(hiddenのvalueが消える)
raty.readOnly(true);    // 読み取り専用に切り替える

並び順には理由があります。cancel()の実装は_isReadOnly()が偽のときだけ本体を実行するため、readOnly(true)のあとにcancel()を呼んでも例外を出さずに素通りします。読み取り専用への切り替えは最後に置いてください。

Rails 8での評価データ保存と読み取り専用表示

SERP上位9本のうち5本がRailsのレビュー機能実装記事で、日本語圏の「raty」需要はここに集中しています。Rails 8.1.3.1(2026-07-30リリース)を前提に、保存から一覧表示までを組み立てます。

半星を保存するdecimalカラムと範囲バリデーション

半星投票を許すなら整数カラムでは足りません。ジェネレータの属性オプションで精度まで指定できます。

rails generate migration AddRatingToReviews rating:decimal{3,1}

この記法はprecision: 3, scale: 1に展開されます。波括弧を省いたrating:decimalだけでは精度指定が付かないので、後からマイグレーションを手で編集することになります。モデル側では範囲を縛ります。

class Review < ApplicationRecord
  validates :rating,
            presence: true,
            numericality: { greater_than: 0, less_than_or_equal_to: 5 }
end

星の数をnumberオプションで5から変えた場合、この上限値も合わせて変更してください。フロントの星の数とサーバーの許容範囲がずれると、UIでは選べないのにバリデーションだけ通る状態が生まれます。

フォーム側の記述とStrong Parameters

ビューではtag.divヘルパーでdata属性を組み立てます。@review.ratingがnilのときRailsは該当のdata属性ごと出力しないため、未評価と評価済みで分岐を書く必要がなくなります。

<%= form_with model: @review do |f| %>
  <%= tag.div(data: { raty: true, score_name: "review[rating]", score: @review.rating&.to_f }) %>
  <%= f.submit "評価を送信" %>
<% end %>

to_fを挟んでいるのは、decimalカラムの値がBigDecimalで返るためです。素のまま渡すとdata-score="0.25e1"という指数表記がHTMLに出ます。Raty側は正しく2.5として解釈しますが、ソースを読んだ人が驚くだけなので浮動小数に落としておきます。

data属性はキャメルケースに変換されて読み込まれるため、score_nameはscoreNameオプションとして解釈されます。コントローラはRails 8で追加されたparams.expectで受けます。

def create
  @review = @product.reviews.build(review_params)

  if @review.save
    redirect_to @product, notice: "評価を保存しました"
  else
    render :new, status: :unprocessable_content
  end
end

private

def review_params
  params.expect(review: [:rating, :body])
end

ステータスシンボルに:unprocessable_contentを使っている点に注意してください。Rack 3.1以降で:unprocessable_entityは非推奨扱いになり、Rails 8.1のscaffoldもActionDispatch::Constants::UNPROCESSABLE_CONTENT経由で新しい方を生成します。

平均評価の算出と一覧での読み取り専用表示

商品一覧に平均点を並べるのが、レビュー機能で最初に求められる表示です。平均はBigDecimalで返るので、丸めてから渡します。

<% @products.each do |product| %>
  <% average = product.reviews.average(:rating)&.round(1) %>
  <%= tag.div(data: { raty: true, read_only: true,
                      score: average&.to_f,
                      path: "/raty" }) %>
  <%= average ? "#{average} (#{product.reviews_count}件)" : "評価はまだありません" %>
<% end %>

平均がnilのときはdata-scoreが出力されず、noRatedMsgの状態になります。件数を毎回COUNTで数えると一覧ページで効いてくるので、reviews_countのようなカウンタを持たせてください。持ち方と後付けの手順はcounter_cacheとは?Railsでの実装手順とカウントずれ・後付けの対処にまとめています。

初期化は1本のスクリプトで全要素をまとめて処理できます。

document.querySelectorAll('[data-raty]').forEach((el) => {
  new Raty(el, {}).init();
});

Propshaft環境でのアセット配置

Rails 8のアプリケーションジェネレータは、既定でpropshaftとimportmap-railsをGemfileに書き込みます。Sprockets前提の古い記事どおりapp/assets/javascriptsへ置いても読まれないので、配置先を先に確認してください。

星のPNGをアセットパイプラインに載せる場合、Propshaftはファイル名にダイジェストを付けて配信します。/assets/raty/star-on-a1b2c3d4.pngのような形になるため、pathにディレクトリ名を書く方法は開発環境でも本番でも404になります。ディレクトリではなくアイコンごとに解決済みのURLを渡し、pathは空文字で無効化します。

<%= tag.div(data: { raty: true, path: "",
                    star_on: asset_path("raty/star-on.png"),
                    star_off: asset_path("raty/star-off.png") }) %>

設定が細かくなるのを避けたいなら、星のPNGだけpublic/raty/に置いてpath: "/raty"で参照する割り切りもあります。ダイジェストが付かないぶんキャッシュ制御は弱くなりますが、5枚の静的画像なら実害は小さいと考えます。raty.cssをパイプラインに載せる場合は、Propshaftがurl()を書き換える対象にfonts/が入っているかも確認してください。

JavaScript側はsrc/raty.jsがES Modulesなので、vendor/javascript/に置いてimportmapにpinできます。アセットパイプラインのコマンドと役割分担はrails assets:clobberとは?precompile・cleanとの違いとアセットパイプライン運用【Rails 8 Propshaft対応】で整理しています。

再評価の許可と、他人の評価を書き換えさせない制御

自分の評価だけ編集可能にする切り替えは、ビュー側の分岐で表現できます。

<%= tag.div(data: { raty: true,
                    score: @review.rating&.to_f,
                    read_only: @review.user_id != current_user&.id }) %>

編集フォームから同じscoreNameで送れば、updateアクションで上書きされます。再投稿を1人1件に保ちたい場合は、validates :user_id, uniqueness: { scope: :product_id }で重複を止めるのが確実です。

ただしreadOnlyはブラウザのUI操作を止めるだけで、hidden fieldにreadonly属性が付くにすぎません。リクエストを直接組み立てれば任意の値を送れるので、更新可否の検証はコントローラに必ず置いてください。認証基盤から用意する場合の選択肢はSorcery gemでRailsに認証機能を実装する手順|Deviseとの違い・最新0.18.0対応で比較しています。

星が出ないときの原因切り分け

ここまでの内容を踏まえると、トラブルの原因はほぼ5つに絞り込めます。

症状とエラーメッセージから見る5つの原因

症状 原因 対処
$(...).raty is not a function v4に旧記法 new Raty() へ書き換え
window.Raty is not a constructor window.Raty を参照 素の Raty を使う
Raty is not defined UMD版を読み込み window.raty.default を使う
divが空・エラーなし init() の呼び忘れ 生成直後に1行追加
星の枠だけ出て画像が壊れる path 未指定 生成された img の src を確認

切り分けの順番は、まずコンソールを見ることです。何も出ていなければinit()とpath、エラーが出ていれば旧記法かグローバル参照の問題と判断できます。

JSのオプションをdata属性が上書きする優先順位

これは公式tutorialに「Data Support」として書かれた正式な機能ですが、優先順位を知らないと原因不明のバグになります。src/raty.jsのコンストラクタは、既定値・引数のオプション・要素のdatasetの順にオブジェクトを展開します。最後に展開されるdatasetが勝つ構造です。

<div data-raty data-score="5">という要素に対して{ score: 1 }を渡すと、適用されるのは5になります。サーバー側でレンダリングしたdata属性が、JS側の共通設定を静かに上書きする事故が起こります。テンプレートで一括初期化している場合は、data属性の出力内容を先に確認してください。

Ratyを採用すべきでない3つの条件

Ratyは依存が無く、hidden fieldの生成まで面倒を見てくれます。それでも次に当てはまるなら別の手段を選ぶべきです。

キーボード操作とスクリーンリーダーへの対応が要件のフォーム

src/raty.jsにはrole・aria-*・tabindex・keydownのいずれも実装されていません。登録しているリスナーはclick・mouseover・mouseleaveだけです。生成されるのはimgまたはi要素の並びなので、キーボードだけで評価を選ぶ操作ができません。フォームコントロールとしての要件を満たすには自前で補うことになり、それならネイティブのinput type="radio"をCSSで星に見せる実装の方が、追加するコードは少なく済みます。

集計・重複防止・多次元評価までRails側で必要な場合

Ratyの作者自身がREADMEの冒頭で「Rating for Rails? It’s Rating」と別gemを案内しています。rating gemは2.1.0が2026-06-30に公開されており、こちらはスコアの集計やスコープ付きの評価をモデル層で扱います。表示だけをRatyに任せ、データモデルはgemに寄せる分担が作者の想定です。

ベンダーの継続更新を前提にした長期保守

4.3.0のリリースは2024-04-28で、リポジトリへの最終pushも同日です。2026-08-05時点で2年以上リリースがなく、オープンなissueは52件、pull requestは7件が残っています。アーカイブはされておらずMITライセンスでコードも小さいため自前保守は現実的ですが、更新が続く前提での選定はできません。新規プロジェクトでこれを許容できるかは、着手前に決めておくべきです。

よくある質問

星の数を5個から増やしたいのですが上限はありますか?

numberオプションで変更でき、上限はnumberMaxの既定値である20個です。{ number: 10 }なら10個の星が並びます。20を超える数を指定した場合はnumberMaxの値で頭打ちになるため、それ以上必要ならnumberMaxも同時に引き上げてください。サーバー側のバリデーション上限も忘れずに合わせます。

星の色や大きさは変えられますか?

starType: 'i'を指定してフォントアイコン版にすると、star-on-pngなどのクラスに対してCSSでcolorとfont-sizeを当てられます。src/raty.cssの既定はfont-size: 2emです。画像版のまま色を変えたい場合は、starOn・starOff・starHalfに自作PNGのファイル名を渡す方法になります。

古いjQuery記法のまま動かし続けることはできますか?

できます。$.fn.ratyを持つ最後のバージョンはraty-js 3.1.1(2021-09-30公開)で、mainがlib/jquery.raty.js、依存にjquery ^3.6が入っています。npm install [email protected]で固定すれば既存コードは動きます。ただし2021年で更新が止まっている系列なので、当面の延命策と考えてください。

Ratyで選んだ評価をAjaxで即時保存できますか?

clickコールバックでスコアを受け取って送信します。v4では引数が(score, element, evt)の3つに変わっている点に注意してください。thisはRatyインスタンスを指します。コールバック内でfalseを返すとクリック自体が取り消され、スコアは変化しません。バリデーションエラー時に選択を戻す用途に使えます。

読み取り専用にすれば評価を改ざんされませんか?

いいえ、防げません。readOnly: trueが行うのは、要素にpointer-events: noneを当て、hidden fieldにreadonly属性を付けることだけです。ブラウザのUI操作を止めるための機能であり、リクエストを直接組み立てれば任意の値を送れます。評価の更新可否はコントローラ側で必ず検証してください。

関連記事

お気に入りに入れた記事の一覧

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.23 テックブログ Renta!不正アクセスでサービス停止:再開未定の現状と運営側の停止判断・証拠保全・段階的再開
  2. 2026.10.21 テックブログ ふるさとチョイス不正アクセスで445万件流出:対象確認・パスワード変更と再開時期
  3. 2026.10.24 テックブログ カプコン不正アクセス:CAPCOM ID 1,177万件漏えいと196件の乗っ取りへの対処
  4. 2026.10.24 テックブログ ブラストメール不正アクセス:配信先288件の漏えいと利用企業の報告・通知の手順
  5. 2026.10.17 コラム カスハラ奨励金とは?東京都40万円の第2回要件と11月6日までに間に合う取組

RELATED POSTS 関連記事

目次