cjmellor/rating
A Laravel package for adding ratings and reviews to your models. Supports polymorphic relationships, multiple rating types, and easy Eloquent integration, letting you attach star ratings or reviews to users, posts, products, and more.
Install the package and publish its assets:
composer require cjmellor/rating
php artisan vendor:publish --tag="rating-config"
php artisan vendor:publish --tag="rating-migrations"
php artisan migrate
Add the Rateable trait to any model you want to be rateable:
use Cjmellor\Rating\Traits\Rateable;
class Post extends Model
{
use Rateable;
}
First use case — the most common flow is a logged-in user rating a model:
$post->rate(5); // default rating type
$post->rate(4, 'star'); // explicit type
$post->averageRating(); // aggregate for display
$post->getRating(); // current user's rating
Where to look first: the published config/rating.php (defines your user_model and allowed rating_types) and app/Models for the trait wiring. Everything else is convention-driven off those two pieces.
Rating types as a first-class concept. The package supports multiple independent rating dimensions on the same model (e.g. star, like, thumbs). Define them once in config and pass the type string through every call — rate, updateRating, unrate, getRating, averageRating all accept it. This is the cleanest way to support "rate the recipe" and "rate the plating" on the same record without separate tables.
Controller / Livewire action pattern. Typical mutation endpoint:
public function store(Request $request, Post $post)
{
$post->rate($request->integer('value'), 'star');
return back();
}
Use updateRating() rather than rate() if the user may already have a rating — it updates in place instead of relying on your own uniqueness guard.
Querying rated content. Use the provided scopes to avoid hand-rolling joins against the ratings table:
Post::whereRatedBy(auth()->user())->get();
Post::whereRated(auth()->user(), 5)->get();
Eager-load ratings when rendering lists that show per-item averages to avoid N+1 queries.
Displaying ratings. For quick UI, the package historically shipped a Livewire component. As of 2.2.0 it is optional — you must have livewire/livewire installed in your app to use it. If you don't want Livewire, treat averageRating() as a plain value and build your own Blade/JS widget around it.
Integration tips.
auth()->user() (per your user_model config).averageRating() per model per type (e.g. via a computed column or Cache::remember) if you render it in listings; the method hits the database each call.livewire/livewire is in your own composer.json. Without it, the rating UI component silently won't resolve.rating_types and user_model are read from config. After editing config/rating.php in production, run php artisan config:clear (or config:cache) or your changes won't take effect.rate() twice for the same user/type generally updates; if you need strict "no re-rating" behaviour, enforce it in a policy or Form Request rather than relying on the trait.rateable_type/rateable_id. If you rename a model class or move namespaces, historical rows break. Keep a mapping migration ready when refactoring model names.min/max in the request layer — the package won't reject an out-of-range integer for you on all paths.averageRating() returns a float. For display you'll want round($post->averageRating(), 1); storing the rounded value defeats the purpose of the aggregate.rate() appears to do nothing, check: (1) the model actually uses Rateable, (2) a user is authenticated, (3) migrations ran, (4) the type string matches a key in rating_types. Wrong-type calls fail quietly rather than throwing in some versions.Rate model via config if you need custom columns; publish migrations and add fields rather than editing vendor files. The trait is thin — overriding rate() in your model is a valid escape hatch for bespoke logic.composer update is safe on L11 projects; pin to ^2.2 to guarantee the Livewire decoupling.How can I help you explore Laravel packages today?