Q:

Ruby on Rails - group_by for relation and created_at

I'm looking for a Rails query that will get me the last created rating for every movie made by the current user.
For example, let's say I have this active record collection:
#<ActiveRecord::Relation [
  #<Rating id: 115, score: 5, movie_id: 7, user_id: 5, created_at: "2019-09-16 16:47:55", updated_at: "2019-09-16 16:47:55">,
  #<Rating id: 116, score: 3, movie_id: 7, user_id: 5, created_at: "2019-09-16 16:47:57", updated_at: "2019-09-16 16:47:57">,
  #<Rating id: 117, score: 5, movie_id: 7, user_id: 5, created_at: "2019-09-16 16:50:37", updated_at: "2019-09-16 16:50:37">,
  #<Rating id: 118, score: 3, movie_id: 8, user_id: 5, created_at: "2019-09-16 16:50:42", updated_at: "2019-09-16 16:50:42">
]>

We can see there are three objects with movie_id: 7, one with movie_id: 6. This is wrong as I need to get the latest rating for each movie from the current_user.
For example, something alone the lines of this:
Rating.order(created_at: :desc).select('DISTINCT ON (movie_id) *')

My model associations:
class Movie < ApplicationRecord
  belongs_to :user
  has_many   :ratings, dependent: :destroy
end

class Rating < ApplicationRecord
  belongs_to :user
  belongs_to :movie
end

class User < ApplicationRecord
  has_many :movies
  has_many :ratings
end

Please explain the Rails query as I really want to understand this.

A:

Let's do it in parts!
You need a Rails query that will get me the last created rating for every movie made by the current user.
Ok, with this information, let`s start with the current_user reference!
Your relation for User is like this:

A user has many movies
A user has many ratings

With these definitions, you can take advantage of ActiveRecord to run the following methods:
current_user.movies # All movies of a current_user
current_user.movies # All ratings of a current_user

Ok, now we can access all movies and ratings from a user instance, but how we can access the ratings grouped by movies?
Let's see the Rating relations:

A rating belongs to a user # this means the rating instance has the user_id
A rating belongs to a movie # this means the rating instance has the movie_id

Nice! Now we can get the user ratings grouped by movie:
current_user.ratings.group_by { |rating| rating.movie_id }
# or the sugar sintax
grouped_ratings = current_user.ratings.group_by(&:movie_id)

This will group all user ratings based on the movie_id, and will produce to us a hash like:
{
  1: [#<Rating id: 115...#>, #<Rating id: 116...#>], # The "1" means the movie_id of the group_by
  2: [#<Rating id: 117...#>] # The "2" means the movie_id of the group_by
}

Ok, now we have a hash of ratings from a User, grouped by the movie_id.
But we need the last rating created by a user for each Movie correctly?
last_ratings_for_each_movie = grouped_ratings.map do |movie_id, ratings|
  movie = Movie.find(movie_id)
  last_rating = ratings.sort_by{ |rating| rating.created_at }.last
  
  puts "The last Rating created by the current user for Movie #{movie.title} is the rating #{last_rating.id}" # Assuming movie has a title
  
  last_rating
end

In the last moment, you will have an array of the last rating created for a movie (to access the movie you can execute a rating.movie for example)
I didn't understand if you must do it with SQL, if yes, let me know pls :)
Hope it helps!

