I use the gem act_as_votable to allow users to select categories they like. To get the categories a user likes:


These categories have children categories, and I need to find the posts in those children categories.

I use this line to do it:

@categories_posts = current_user.get_voted(Category).flat_map { |category| category.children.flat_map(&:posts)}.delete_if{ |post| post.status == "draft"}

But I noticed in my logs that this was doing way too much computation for this task.

Is there a way to make it lighter ?


1 Answer 1


Some notes:

  • You should limit the lines to 80/100 chars.
  • When a call chain seems to include too much logic, move it to methods/class-methods of models.

As a first refactor, I'd implement Category#with_children and then write:

@categories_posts = current_user.
  reject { |post| post.status == "draft" }

On a second refactor, it's nice to have relations instead of arrays as output. This way you can use scopes, paginators and such, even if you cannot directly use has_many here (because of the recursive category requirement):

categories = current_user.get_voted(Category).flat_map(&:with_children)
@categories_posts = Post.where(category: categories).published

That's to show the implementation, on the controller you should still have less logic, something like this: @categories_posts = current_user.posts_of_voted_categories.published.

  • \$\begingroup\$ Thanks for your input ! This indeed makes the code more readable, but does it make it more efficient ? \$\endgroup\$ Jul 12, 2016 at 20:12
  • \$\begingroup\$ Updated, now it should be more efficient, it's using SQL from the category level. \$\endgroup\$
    – tokland
    Jul 13, 2016 at 7:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.