Creating a Ruby gem for one-time announcements, part 3 – targeting messages to users

This is part 3 of building a gem for targeted, one-time announcements to users in Rails. See part 2 and part 1.

We’ll focus on targeting announcements to certain types of users. For instance, the admin may want to deliver an announcement only to users who have subscriptions.

A field in the Announcements table called limit_to_users will specify which types of users should receive the announcement.

limit_to_users can contain multiple conditions, so we’ll make it an array of hashes. ActiveRecord allows objects like these to be stored in text fields in the database, using the serialize method in a model.

This test validates that the field works as intended, storing conditions and allowing them to be retrieved. Here, we are sharing the announcement only with users who do not have a subscription.

Querying serialized fields is tough

It’s risky to query serialized fields in a relational database. MongoDB and similar noSQL databases are tuned for fast queries of free-form information, while Postgres and its SQL siblings are not.

We need to figure out which announcement to serve to which user, even though the conditions are stored in a query-resistant serialized field.

Houston, we’ve got loops

Maybe we should grab all active announcements that the current user has not read, and cycle through them to find the latest one that is relevant to the user.

My first try at this includes two loops, one inside the other, which:

  1. Cycle through each active, unread announcement
  2. For each announcement, cycle through each condition

Loops carry potential performance issues, especially when nested. In this case, we came as far as we could with a query, and used loops for the rest.

The loops do not re-query the database, thus avoiding an n+1 query problem, so they should be pretty quick. We’ll test performance in past 4, coming soon. brings Rails job offers to you. Free for candidates. Salaries from $75,000 to $250,000. Sign up now!

Leave a Reply