Sort collection of models by last added (to collection)

Hey all,

I’m working on a site that has a model Set and a model Cart. Set belongs_to Cart and Cart has_many Sets. I’m using ruby’s append method to add a set to the cart.

Cart.sets << set

On the shopping page, I have a list of the sets in the current_cart. They should display in the order that the sets were added to the cart, and for the most part that is the case. Occasionally, though, a set being added to the cart will jump to the middle of the pack, and I can’t figure out why. I know that the sets aren’t being sorted by ID because in my current list set 4 is first followed by 2 and 3 (the correct order).

Also, if I were to delete set 4 (from the first position) and re-add the set to the cart it will jump back to the first spot. I feel like I’m missing something obvious here.

Any ideas?

The “shovel” operator creates an association in the database. When you retrieve the records from the database, the sort is non-deterministic. You didn’t give it any constraints so your database returns them in whatever order it happened to retrieve the records.

It sounds like you need a cart/sets join model so you can use the created_at field for sorting.

Thanks for your reply @derekprior. I actually do have a join model called cart_set, but I’m unsure of how to sort by using created_at on the join model. I’ll keep digging!

So I’ve managed to get it to work, but it’s pretty dirty. What would be a more ideal way to do this?

<% CartIconSet.where(cart: current_cart).order('created_at').each do |set| %>
    <% set = IconSet.find(set.icon_set) %>
    ....
<% end %>

^— I feel really bad for doing this.

What about?

current_cart.cart_icon_sets.order(:created_at).includes(:set)

Assuming the relationships are set up like that, that should fetch you the icon sets for the current cart. The includes means when you are iterating over the cart_icon_sets you can call set to get the associated set record without doing another database round trip.

1 Like

I got it working. Still messy, but it’s down to one line.

<% current_cart.cart_icon_sets.order('created_at').map(&:icon_set).each do |set| %>

I’m not sure why I couldn’t get it to work with includes but I’ll see if I can’t figure it out. Thanks!