append to an active record relations object
Solution 1
You could do something like this:
def index
posts_ids = []
Category.most_popular.limit(20).each do |cat|
post_ids << Post.enabled.recent.by_category(cat).map(&:id)
end
@posts = Post.find( post_ids ).page(1).per(30)
end
Solution 2
Let me define your problem to ensure that I understand it correctly. In your view, you want the latest post of each category first. And then you want all posts ordered by their recentness.
I would create two instance variables in the controller to be later used in the view.
def index
enabled_posts = Post.enabled.recent
@category_posts = enabled_posts.joins(:categories).group("categories.id")
exclude_post_ids = @category_posts.pluck("posts.id")
@posts = enabled_posts.where("id NOT IN (?)", exclude_post_ids)
end
The above should be convenient if you're using two different sections to display @category_posts
and the remaining posts. But if you're using a single section and you want all the posts ordered in a single variable, then simply change your controller code to the following:
def index
enabled_posts = Post.enabled.recent
category_posts = enabled_posts.joins(:categories).group("categories.id")
exclude_post_ids = @category_posts.pluck("posts.id")
remaining_posts = enabled_posts.where("id NOT IN (?)", exclude_post_ids)
@posts = category_posts + remaining_posts
end
inquisitive
A quick learner. An Inquisitive. Worked a bit on Android, RoR and the MEEN Stack. Currently working on Golang+React
Updated on June 04, 2022Comments
-
inquisitive almost 2 years
I have a Post model. Having a scope which finds the enabled posts.A post can belong to a category. I also have a Category model, with categories ranked. Category has many posts. I want to display first distinct 20 posts which belong to distinct categories(which are the top 20 categories) and then display the rest of the post in descending order of their published_time.
This is what I have
Post model
:class Post < ActiveRecord::Base belongs_to :categories scope :by_category, ->(category) { joins(categories).where(categories: { id: category.id }) } scope :enabled, where(disabled: false) scope :recent, order('published_at DESC')
Category model
class Category < ActiveRecord::Base has_many :feeds scope :most_popular, order('rank ASC')
Home Controller
def index Category.most_popular.limit(20).each do |cat| @posts= Post.enabled.recent.by_category(cat).page(1).per(30) end
in view file I am rendering the attributes of the post that i receive using @posts. But as obvious, it returns only the post of the last category found in the loop. Basically it doesn't append. I tried using << to append.. as in -
@posts << Post.enabled.recent.by_category(cat).page(1).per(30)
But it gives no method << for nil:nil class
I tried making @posts as an array, but then it does not take page and per of kaminari into play.
I tried making @posts as ActiveRecord::Relation object using new, it gave argument error.
I tried making @posts as object of Post but then it says undefined method << for Post, since ofcourse, << is not a method for my model class. I also followed some SO posts but it didn't seem to fit in my step.
Basically, my insight into achieving this was appending records into the model object and then displaying the object. I even doubt, if my approach is good enough. There could be more efficient way of doing this, which I may be missing out in RoR.