Homepage

Ruby: Count Articles by Category [Elastic Search]

Have you ever wanted to count how many articles will be left in a certain category after search? To give you an idea of what I mean, as an example let’s use the application that will be the outcome of this tutorial. Our database contains music albums which are categorized by the genre and subgenre.

Have you ever wanted to count how many articles will be left in a certain category after search? To give you an idea of what I mean, as an example let’s use the application that will be the outcome of this tutorial. Our database contains music albums which are categorized by the genre and subgenre.

After searching for, let’s say ‘Miles’ the album count in a category will change according to how many articles (albums in this case) meet the search requirement.

My solution utilizes Ruby on Rails elastic aggregations and Drapper. The best thing about it is that it doesn’t make additional requests to the database. Elastic makes the searching process much easier and faster. A solution on the basis of a database is much more time-consuming to develop and heavier on the server than mine.

The only downside I can think of is that you need to create an additional service.

Steps

I'll skip steps taken to create the app and to add some layout. I'll use controller articles with action index for listing and search.

Install prerequisites:

  • Elastic search or use docker image

  • Add these gems to the Gemfile:

    • gem 'elasticsearch-model'

    • gem 'elasticsearch-rails'

    • gem 'draper'

  • Github: 'drapergem/draper'

  • Bundle install

  • Add elastic initializer to point elastic host

tsx

Create models:

tsx

Create a decorator for the Category:

tsx

Add attr_accessor :article_count to the decorator of the class.

Create collection decorator

Add an apply_counts method with a buckets_counts argument.

tsx

Later this will allow to set the article_count based on aggregations.

Add module Searchable to concerns

tsx

The Article model

Include Searchable:

Add associations:

tsx

Delegate author_name:

tsx

In the models folder create Articles::Index module to define the elastic index:

tsx

type: :text is for thetext search.

indexes :category_ids and type: :integer will allow to aggregate the results by category.

Include the Articles::Index in Article model.

Seed data

I've prepared the seed with some jazz albums with assigned jazz sub-genres.

tsx

The last two lines in the seed create the index in elastic, so:

tsx

Now we can take care of searching and aggregates.

Oh look! We're halfway through the post! Here's a picture of a cute kitten:

Add a simple class for the search form:

tsx

Add search query object:

tsx

Search with elastic could be as simple as Article.search(search_text).records.to_a but we can ask elastic to count something for us in one go.

To do this we will need a little bit more complex query which we'll prepare using elastic DSL and put as an argument to the search method.

All methods beneath are private.

Search definition object will do almost the same thing as the search above.

tsx

Attributes :size, :from are for paging, default elastic page size is 10.

How to add aggregations? Using elastic DSL allows us to define aggs criteria:

tsx

And add them to search definition object:

tsx

Result of our query object at the end should look like a.e.

tsx

When we assign a search object to a search variable as search = Article.search(query) then we check search.response on search object which should look like this:

tsx

In aggregations => by_categories we can find buckets and that's what we're interested in! Key buckets contain counts for category_ids.

Extract them:

tsx

Map categories_ids:

tsx

Prepare the bucket hash:

tsx

Find categories, decorate the collection and apply counts:

tsx

Update public method call:

tsx

We will return object with categories and articles.

Last step is to add some logic to ArticlesController

tsx

Working app

That's all, you can check working example downloading repo:

  • Clone or download repo

  • Install docker if needed

  • Run

tsx

Let’s Create a Great Website Together

We'll shape your web platform the way you win it!

More posts in this category

  • February 05, 2025 • 10 min read

    API-first CMS: What Options You Have (Web Dev Agency's Take)

    According to the 2024 State of the API Report by Postman, 74% of organizations are adopting API-first strategies. This statistic isn’t just impressive—it signals a major shift in how businesses operate. While API-first approaches have long been a staple in software development, they're now reshaping content management as well. More and more companies are realizing that traditional CMS platforms can't keep up with the demand for flexibility, speed, and seamless integrations.

    READ MORELearn more about api first cms
  • January 23, 2025 • 15 min read

    Best CMS for SaaS: Top Cloud-Based Solutions

    Choosing the right Content Management System (CMS) is a critical decision for your SaaS business. Your unique needs require solutions that are not only flexible, scalable, and user-friendly but also tailored to meet the demands of a fast-paced, customer-focused industry. A CMS should simplify your workflows and help you deliver personalized, high-quality digital experiences.

    READ MORELearn more about best cms for saas top cloud based solutions
  • December 12, 2024 • 10 min read

    We Picked the Best (Headless) CMS for Vue

    Picture a digital experience where content effortlessly flows across platforms, development is agile, and performance is unmatched. By combining the power of Vue.js, a progressive JavaScript framework, with a modern headless CMS, you can achieve all this and more.

    READ MORELearn more about headless cms for vue