order by association's count of another model, limit to 1 - ruby-on-rails

I want to display a gallery of magazines that shows the newest issue for each magazine title, but ordered by the number of subscriptions on that magazine. I came up with this query
class IssuesController < ApplicationController
def index
#issues = Issue
.includes(:magazine)
.order('magazines.subscriptions_count DESC')
.order(:release)
.paginate(page: #page, per_page: 25)
end
end
It correctly orders them by the suscriptions_count, however there are many entries for each magazine, each issue is displayed in order. I just want the first magazine for each one. I've tried adding uniq to the query, group(:magazine_id), limit(1), and more but I can't get it to only display one issue per magazine title.

I found this answer PostgreSQL -must appear in the GROUP BY clause or be used in an aggregate function
which lead me to select("DISTINCT_ON('magazine_id') *"). Works perfectly, only showing a single entry for each magazine_id
def index
#issues = Issue
.includes(:magazine)
.select("DISTINCT ON (magazine_id, magazines.subscriptions_count) *")
.order('comics.subscriptions_count DESC')
.paginate(page: #page, per_page: 25)
end

Related

Pagination breaks when I add a join and group statement to a query?

I have an index page with Subscriptions. A Subscription has_many SubscriptionVersions and I need to order them based on the latest SubscriptionVersions authorized_at date.
This is my controller action
def index
#subscriptions = current_account.subscriptions
.includes(:plan, :user)
.joins("INNER JOIN subscription_versions
ON subscription_versions.subscription_id = subscriptions.id")
.group("plans.id, subscriptions.id, users.id")
.order("MAX(subscription_versions.authorized_at) ASC")
.paginate(page: params[:page], per_page: 20)
end
Removing the join and order statements, pagination works fine, but if I add them the results are not paginated.
What is going on and why?

Rails scope that orders Users by a Reputation Score

I have a users table and I keep a reputation score on each user. The reputation score is the combined score from 2 factors:
total followers on the Users projects (projects he/she created)
total votes on the Users tasks (tasks that he/she created)
My goal is to allow users to filter users by most recent (the standard index action) or by users with the most reputation. What Rails scope would give back the list of Users ordered by this 'total reputation score' in order of highest score to lowest? thx,
My code is as follows:
User.RB Model
def total_reputation_score
project_follower_count + task_vote_count
end
scope :by_reputation, -> { #HOW DO I CREATE THIS SCOPE? }
Users Controller
def index
#users = User.text_search(params[:query]).paginate(page: params[:page], :per_page => 12)
end
def most_reputation
#users = policy_scope(User)
#users = #users.
text_search(params[:query]).
by_reputation.
paginate(page: params[:page], :per_page => 12)
render :index
end
While you can do this in SQL on the fly, you really want to:
Add a counter cache for each of the two count items shown here; this adds these as calculated columns that Rails will maintain for you, then do this for your scope:
User.order(User.arel_table[:project_follower_count] + User.arel_table[:task_vote_count]).reverse_order
(or something similar)
Alternately you can double down on your RDBMS and build out indices to handle on the fly.

Will_Paginate Gem With Rails Displaying Results In Wrong Order

Attempting to sort an entry by an associated field, unfortunately when paginating with Will Paginate the sorting is wrong.
#categories = Category.includes(:posts)
.page(params[:page])
.order("posts.post_at DESC")
I have tried many variations, but unfortunately will paginate does not seem to respect the sort order of categories. Without the pagination the categories are sorted correctly.
How can I get Will Paginate to respect the order?
The end goal is Categories sorted by posts.post_at and paginated while maintaining that order.
Thanks.
Try
#categories = Category.includes(:posts).order("posts.post_at DESC").paginate(:page => params[:page], :per_page => 10)
Sorry can't comment due to low rep, but what are you trying to sort by and what do you want listed?
If you want categories in a certain order with the associated posts, is that by alphabetical?
#categories = Category.includes(:posts).order('categories.name??').page(params[:page])
Category with most recent posts?
#categories = Category.includes(:posts).order("posts.post_at DESC").page(params[:page])
Or are you wanting the most recent posts with the categories listed along with it?
#posts = Post.includes(:category).order('posts.post_at DESC').page(params[:page])
It's unclear what your end goal is with this query.

rails tire elasticsearch weird error

I have indexed a Car model with one car record mercedes benz in the database. If I search for the word benz I get an error:
ActiveRecord::RecordNotFound in CarsController#index
Couldn't find all Cars with IDs (1, 3) (found 1 results, but was looking for 2)
If I search for hello I get:
Couldn't find Car with id=2
Other random search terms work returning accurate results.
So it's basically random errors generated by random search terms. What could be the cause of this?
Controller:
def index
if params[:query].present?
#cars = Car.search(params)
else
#cars = Car.paginate(:page => params[:page], :per_page => 10)
end
end
Model:
def self.search(params)
tire.search(load: true, page: params[:page], per_page: 10) do |s|
s.query { string params[:query]} if params[:query].present?
end
end
This happens because, you are using the load => true option to load the search results from database. The activerecord seems to be missing in DB, but the elasticsearch index contains the same document.
Reindex is not always the solution IMHO.
The best solution is to delete the document when it is deleted in db. You can use the after_destroy callback for this.
Tire remove api is used to remove a single document from index.
Tire.index('my-index-name').remove('my-document-type', 'my-document-id')
Reference: https://github.com/karmi/tire/issues/43

show only posts created in last week

I want to be able to show posts and have them sorted by a couple criteria, first by the amount of votes they have on them and second by the date at which they were created. I don't want posts that are more than a week old being displayed so only posts in the last week. I tried doing this:
<%= render #posts.sort_by { |post| post.votes.count if post.created_at < 1.week.ago.utc }.reverse %>
but it gave me an error of comparison of NilClass with 2 failed
I know the code works by just sorting posts by vote count but I also want to limit time so could someone tell me how this can be done. I'm still new so sorry for the simplicity.
Solution by #Salil is ok, but I would suggest adding counter_cache column ( http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html ) and changing recent_post code (from this comment: https://stackoverflow.com/a/11498634/1392074 ) into:
def self.recent_posts
Post.where("created_at >= ?", 1.week.ago.utc).order("votes_count DESC, created_at DESC")
end
The code to find posts should be in Model and not on Views.
There is always a good idea that you should fetch the records which we need to display instead fetching the records and showing some of it on views.
You should do something like following
in your post.rb
def self.recent_posts
Post.select("p.*, COUNT(v.id) AS count").where("post.created_at >= 1.week.ago.utc").joins("p LEFT JOIN votes v on p.id=v.post_id").order("count, created_at DESC")
end

Resources