Simon M.
Simon M.

Reputation: 2482

Order a model from an associate table

I have a model that I call "Idee" and I want to order this model by date and popularity (there is a voting system for that). I have followed this railcast. And it works but only for the date, the votes are stored in the Vote table, here is my association:

Vote

belongs_to :idee
belongs_to :user

User has_many :votes, dependent: :destroy

Idee has_many :votes, dependent: :destroy

And I don't know how can I say that the Idee are order by vote because the count of vote is made on the Vote table and not in Idee so if I said to sort by vote he want to find a column vote in my Idee. So here is what I have done for now :

Application Helper

def sortable(column, title = nil)
   title ||= column.titleize
   direction = (column == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
   link_to title, :sort => column, :direction => direction
end

Controller

  def publiee
  @idees = Idee.order(sort_column + " " + sort_direction)
  @activites = Activite.all
  end

    private
  def sort_column
    params[:sort] || "created_at"
  end

  def sort_direction
    params[:direction] || "asc"
  end

View

<%= sortable "created_at", "Date" %>

Is there a way to do what I want with what I've done for now ?

PS: My "Idee" are not display in a <table>

Upvotes: 1

Views: 77

Answers (2)

Surya
Surya

Reputation: 16022

in Idee model class:

scope :with_votes_count, -> { select("idees.*, count(votes.id) as votes_count").references(:votes).includes(:votes).group('idees.id') }

then in controller:

def publiee
  @idees = Idee.with_votes_count.order("#{sort_column} #{sort_direction}")
  @activites = Activite.all
end

private
def sort_column
  column = params[:sort] || 'created_at'
  Idee.columns.include?(column) ? column : "created_at"
end

Now, all you have to do is pass sort_column as "votes_count" and sort_direction as "DESC" or "ASC" as you wish to make it work.

Upvotes: 0

Arup Rakshit
Arup Rakshit

Reputation: 118299

Do use joins.

def publiee
  @idees = Idee.order_idess_by_votes sort_column, sort_direction
  @activites = Activite.all
end

Inside the Idee model the below code should go

scope :order_idess_by_votes, ->(sort_column, direction) { joins(:votes).order("#{order_expr(sort_column, direction)}, COUNT(votes.id) DESC)") }

private 

def order_expr sort_column, direction
  # list all possible columns that you want to use in ORDER clause
  # to SQL
  order_mappings = {
    'first_name_asc'  => 'first_name ASC',
    'first_name_desc' => 'first_name DESC',
    'created_at_asc'  => 'created_at ASC',
    'created_at_desc' => 'created_at DESC',
    # .....
  }

  order_mappings["#{sort_column}_{direction}"]
end

Upvotes: 2

Related Questions