1

In a Ruby on Rails application, I have a class called Members with each object having an attribute called executive position that is one of the strings in this array

@executive = ['President', 'Vice President', 'Treasurer', 'Secretary', 'Director of Programs', 'Director of Strategic Partnerships', 'Director of Public Relations', 'Director of Publications', 'Director of Community Service', 'Director of Fundraising', 'Historian', 'Digital Administrator']

I want to sort them in this order, showing the president first, then Vice President etc.

Member.all.sort_by {|member| member.executive_position == @executive}
1
  • Member.all.sort_by { |member| @executive.include? member.executive_position } Commented Sep 12, 2016 at 8:02

3 Answers 3

2
Member.all.sort_by { |member| @executive.index(member.executive_position) }
Sign up to request clarification or add additional context in comments.

Comments

0
Member.all.sort_by { |member| @executive.index(member.executive_position) }

If this is used in other places also, I would go on further to add a method in the Member model like this:

# member.rb
class Member < ActiveRecord::Base
  ...
  EXECUTIVES = ['President', 'Vice President', 'Treasurer',
    'Secretary', 'Director of Programs', 'Director of Strategic Partnerships', 
    'Director of Public Relations', 'Director of Publications', 
    'Director of Community Service', 'Director of Fundraising', 
    'Historian', 'Digital Administrator']

  def position
    EXECUTIVES.index(executive_position)
  end

end

Then the code will be

Member.all.sort_by { |member| member.position }

or shorter

Member.all.sort_by(&:position)

Comments

0

I think you have the logic in the wrong place. You should be using an SQL CASE statement to do the sorting inside the database, that will make it easier to combine this sorting with other query components (such as subqueries and secondary sorting keys). For example, you could have a constant like this:

EXECUTIVES = [ 'President', ... ]

and then a scope like this in your model:

def self.order_by_rank
  q = connection.method(:quote)
  order([
    'case members.executive_position',
    *EXECUTIVES.length.each_with_index.map { |s, i| "when #{q[s]} then #{i}" },
    "else #{EXECUTIVES.length}",
    'end'
  ].join(' '))
end

With that you could say things like:

Member.order_by_rank
Member.where(...).order_by_rank.order(:name)

A straight forward modification to the order_by_rank scope would give you an in_this_order('President', 'Vice President', 'Treasurer', ...) scope:

def self.in_this_order(*titles)
  q = connection.method(:quote)
  order([
    'case members.executive_position',
    *titles.each_with_index.map { |s, i| "when #{q[s]} then #{i}" },
    "else #{titles.length}",
    'end'
  ].join(' '))
end

You could also put the titles and their order in a database table:

title            | pos
-----------------+----
'President'      | 1
'Vice President' | 2
...

and then JOIN to it and ORDER BY pos.

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.