2

I have an array of users which may or may not have an array of startups. The startup object has a property name.

I want to sort the array of users by the name of the startup. But I obviously get an error when the user object does have a startup.

I tried the following code after going through some of the solutions on StackOverflow. I'm using HAML thats why no "end" keyword

- @users.sort do |a, b|
  - a.startup.nil? ? -1 : b.startup.nil? ? 1 : a.startup[0].name <=> b. startup[0].name

but I got the following error.

undefined method `name' for nil:NilClass

On trying

- @users.sort do |a, b|
  - a.startup[0].nil? ? -1 : b.startup[0].nil? ? 1 : a.startup[0].name <=> b. startup[0].name

The users array was not sorted at all.

Note: I referred to this SO post Sorting an array of arrays in Ruby

I also tried

  -@users.sort{|a,b| a.startup[0].name && b.startup[0].name ? a.startup[0].name <=> b.startup[0].name : a.startup[0].name ? -1 : 1 }

which is essentially

foo.sort{|a,b| a && b ? a <=> b : a ? -1 : 1 }

from the SO entry: sorting a ruby array of objects by an attribute that could be nil

even this gave the error

undefined method `name' for nil:NilClass

EDIT: When the user does not have a startup, I want that user to be placed at the end of the array.

Community
  • 1
  • 1
AragornStack
  • 53
  • 1
  • 10
  • If a user doesn't have a startup, then how do you want to sort those? – Tacoman667 Jun 18 '14 at 22:10
  • To put you on the right track, you might review what evaluates to nil in Ruby. (Or to be less subtle, what happens when `User#startup` returns an empty array?) – colinm Jun 18 '14 at 22:17
  • @Tacoman667 When the user does not have a startup, I want that user to be placed at the end of the array. – AragornStack Jun 18 '14 at 22:49

2 Answers2

7

First, you probably want to do this sorting in your controller, or even in your model. Putting it in your view makes it a bit noisy.

Second, this solution should work for you. It's fairly short.

@users.sort_by { |u| u.startup.nil? || u.startup.blank? ? 255.chr : u.startup[0].name }

Using 255.chr will push all empty ([]) and null (nil) arrays to the back of the array, as you specified in your comment that you'd like to do that. I assume that there's a cleaner way of representing 255.chr, but I haven't been able to find one.

If a user with no startups is represented as an empty array ([]), then you can remove u.startup.nil? || from that line of code. Similarly, if a user with no startups is represented as nil, then you can remove || u.startup.blank? from it. The code as is assumes that a user with no startups can either have an empty or null array.

Joe Kennedy
  • 9,365
  • 7
  • 41
  • 55
0

To simplify the problem, you can use #sort_by instead of sort, which only requires you to tell what value should be used to compare things.

@users.sort_by {|u| u.startup.try(:first).try(:name) ? 0 : 1 }

We can also use #try to return nil if the method does not respond to the method we asked.

If you still get errors you should use the try method where you print the startup name

Ismael Abreu
  • 16,443
  • 6
  • 61
  • 75