1

The RoR App has posts and categories, the main view is a row set of categories/posts. It shows posts (newer than 3 days) per category. Empty categories are not shown.

I want to sort the index view to show first the categories with more recent posts. So when a new post is created for a category, the category goes up to the first "row" of the app. Inside a category, posts should be also sorted from newer to older.

Therefore I need to implement two levels of sorting, categories with newest post go first and posts are sorted by creation date inside a category. I am really stuck, how would you implement this?

My controller:

def index
@categories = Category.includes(:posts).select{|c| c.posts.where(['created_at > ?', 3.days.ago]).count > 0} 
end

My view:

 <% @categories.each do |category| %>
  # show category name
     <% category.posts.where(['created_at > ?', 3.days.ago]).each do |post| %>
     # show post title and date
     <% end %>
  <% end %>

UPDATE: to show what I've tried so far:

I tried to sort the @categories first, based on the posts' creation_date (as explained, Category has_many:posts). In my controller:

@categories = Category.includes(:posts).order('posts.created_at').select{|c| c.posts.where(['created_at > ?', 3.days.ago]).count > 0} 

Then in my view, sort the posts as they are loaded:

 <% @categories.each do |category| %>
  # show category name
     <% category.posts.order('created_at').where(['created_at > ?', 3.days.ago]).each do |post| %>
     # show post title and date
     <% end %>
  <% end %>

Regarding the counter_cache sugestion; I understand it'd be only for optimization of database calls, although not strictly necessary.

SOLUTION: it can be done as stated in the previous UPDATE; but with the change of order('posts.created_at') per order('posts.created_at DESC') in the controller; and the change of order('created_at') per order('created_at DESC') in the view.

2
  • 2
    You should show us what you've done so far - regarding the sorting. Commented Mar 16, 2015 at 17:14
  • It seems to be a typical usage of counter_cache: railscasts.com/episodes/23-counter-cache-column Commented Mar 16, 2015 at 17:20

2 Answers 2

1

Can you try the following? (sorry for the joins but it will be faster)

Category.joins(:posts)
        .select('categories.*')
        .group('categories.id')
        .where('posts.created_at > ?', 30.days.ago)
        .having('COUNT(posts.*) > 0')
        .order('posts.created_at DESC')
Sign up to request clarification or add additional context in comments.

2 Comments

It gives me syntax errors like: SQLite3::SQLException: near "*": syntax error: SELECT categories.* FROM "categories" INNER JOIN "posts" ON "posts"."category_id" = "categories"."id" WHERE (posts.created_at > '2015-02-16 18:53:39.638342') GROUP BY categories.id HAVING COUNT(posts.*) > 0 ORDER BY posts.created_at DESC I don't know how to manage :joins; but your proposal geve me the key as the posts need to be sorted by created_at DESC. I was missing the DESC; the same for categories.
Regarding the .includes vs .joins; based in what is explain here [link]tomdallimore.com/blog/includes-vs-joins-in-rails-when-and-where ; and considering my expected number of categories <15; I think the optimal in this case is to use .includes to eage load everything from the begining and save later database queries. Anyway, thanks a lot MrYoshiji
0

See SOLUTION in the original post. Thanks a lot to all the open-handed contributors.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.