Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Envek/eef050e5e243434e904d1478d697e83b to your computer and use it in GitHub Desktop.
Save Envek/eef050e5e243434e904d1478d697e83b to your computer and use it in GitHub Desktop.
Preload first N records of an association in ActiveRecord (Ruby on Rails)
# Collection has and belongs to many Projects through CollectionProject
# Usage
@collections = current_user.collections.page(1)
ActiveRecord::Associations::Preloader.new.preload(@collections, :projects, limited_projects(3))
# Now @collections.first.projects will have only first 3 projects accessible
# Constructs SQL like this to preload limited number of recent projects along with collections:
# SELECT * FROM (
# SELECT "projects".*, row_number() OVER (PARTITION BY collection_projects.collection_id ORDER BY collection_projects.created_at) AS collection_position
# FROM "projects" INNER JOIN "collection_projects" ON "collection_projects"."project_id" = "projects"."id"
# )
# WHERE collection_position <= :limit
def limited_projects(limit)
collection_projects = CollectionProject.arel_table
projects = Project.arel_table
window = Arel::Nodes::Window.new.partition(collection_projects[:collection_id]).order(collection_projects[:created_at])
row_number = Arel::Nodes::NamedFunction.new("row_number", []).over(window)
projects_with_collection_position = Project.all.select(projects[Arel.star], row_number).joins(:collection_projects)
Project.from(projects_with_collection_position, :projects).where("row_number <= :limit", {limit: limit})
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment