9

For example lets assume I have a model called Products and in the Products controller I have the following code for the product_list view to display products sorted.

@products = Product.order(params[:order_by])

And lets imagine in the product_list view the user is able to sort by price, rating, weight etc using a dropdown. The products in the database won't change frequently.

What i'm having a hard time understanding is whether rails will have to query each time when the user selects a new order_by filter or will rails somehow able to cache the active records for re-sorting on the server side? Is there a way to write it so rails won't re query the result if the user sorts? (ie if the product table does not change frequently so there is no point in making a query if the user just want to sort by a different variable)

Thanks,

zjwang
  • 425
  • 6
  • 18
  • How/where are you caching the ActiveRecord objects? The objects don't remain in memory between requests if they are just in an instance variable. Are they stored in memcache or something similar? If you don't want to run another query to retrieve the objects you could do the sorting client side (in javascript). – Coenwulf Feb 26 '14 at 18:18
  • To add to @Coenwulf, I've found the DataTables plugin for jquery to be helpful when displaying lists of objects. It comes built in with sorting capabilities. [link](https://datatables.net) – T J Feb 26 '14 at 18:30
  • OFF TOPIC: do NOT do this `Product.order(params[:order_by])` this is one of the areas where activerecord will not sanitize user input - it is open to sql injection attacks, read this http://stackoverflow.com/questions/7771103/rails-3-activerecord-order-what-is-the-proper-sql-injection-work-around for more info – house9 Feb 26 '14 at 18:43
  • @Coenwulf I'm not caching the objects on the client side. I was wondering if rails does any behind the scenes caching on the server side. I'm guessing you are saying refreshing the view with a different order_by param will always result in a complete new query and rails does nothing to optimize it? – zjwang Feb 26 '14 at 18:46
  • 1
    @house9 Thanks, i'm actually using the railscast method. The above code was just to keep it simple – zjwang Feb 26 '14 at 18:49

1 Answers1

13

You are probably looking for the sort_by method. It will allow you to sort a collection on the server side without using any active record query.

This code result :

@products = Product.all
@products = @products.sort_by {|product| product.name} # Ruby Sorting

should be the same as

@products = Product.order(:name) # SQL sorting
Uelb
  • 3,947
  • 2
  • 21
  • 32
  • At [approximately] what point/size does doing this become slower than simply using active record's order method? – michaelsking1993 Nov 13 '17 at 17:52
  • I would say, if you can do an SQL sorting, just go for it, it should always be faster. – Uelb Nov 14 '17 at 13:57
  • Interesting... I was under the impression that if you can avoid re-querying the database, you should. So if I do `Product.where("name LIKE ?", "n%")`, it would require an extra query to then do `.order(:created_at)`. Is that a false assumption? And wouldn't that be the point of the above question? – michaelsking1993 Nov 15 '17 at 15:39
  • It actually depends if you use the result of the first query. If you write a = Product.where(...) and then do something like a.each, then you can think about sorting in ruby. But if you never use the result a in a way that you need access to the data, then the request is not done. It's only done when the application needs access to it – Uelb Nov 15 '17 at 16:21
  • So let's say I have 100,000 products. Company a (@company) has 30,000 of them. If I do `@company.products.where(importance: (1..2000).to_a)`, is that quicker than doing `@company.products.select{|prod| prod.importance > 0 && prod.importance < 2001}`? – michaelsking1993 Nov 16 '17 at 20:54
  • 1
    The quickest way is the third one : `@company.products.where('importance > 0 AND importance < 2001)` – Uelb Nov 17 '17 at 17:02