Rails query syntax - ruby-on-rails

I'm kinda new on the Rails boat, I would like to know the difference between two types of syntax for queries
The first one I tried is:
User.limit(8).order('created_at DESC').group('created_at').count
The second, which seems to be far more efficient and powerful:
User.count(:order =>'DATE(created_at) DESC', :group =>["DATE(created_at)"], :limit => 8)
But I don't really understand the use case for both.
I'm sure this is something obvious anyway...
Thanks!

The first one is rails 3 syntax. And each method used there, i.e, limit, order, group are ActiveRecord:: Relation method. There are various advantages in using the 1st method. ActiveRecord::Relation is one of the core features of rails 3 apart from asset pipeline etc.
Please read this,
http://asciicasts.com/episodes/239-activerecord-relation-walkthrough

Well the second syntax is the deprecated, old-school, syntax. Also known as Hash-Options-Overload. The first, chaining, syntax is the way forward.

The second one is the powerful and efficient. Because first one will take all the rows (and all the columns) and then it will count. But the second one will perform only counting the rows.
Second one will use the following query.
select count(*) from tablename;

Related

Is there any diferrence between includes(:associations).references(:associations) and eager_load(:associations) in Ruby on Rails 5?

It seems includes(:associations).references(:associations) and eager_load(:associations) execute exactly the same SQL (LEFT OUTER JOIN) in Rails 5. So when do I need to use includes(:associations).references(:associations) syntax?
For example,
Parent.includes(:children1, :children2).references(:children1).where('(some conditions of children1)')
can be converted to
Parent.eager_load(:children1).preload(:children2).where('(some conditions of children1)')
I think the latter (query using eager_load and preload) is simpler and looks better.
UPDATE
I found a strange behavior in my environment (rails 5.2.4.3).
Even when I includes several associations and references only one of them, all the associations I included are LEFT OUTER JOINed.
For example,
Parent.includes(:c1, :c2, :c3).references(:c1).to_sql
executes a SQL which LEFT OUTER JOINs all of c1, c2, c3.
I thought it joins only c1.
Indeed, includes + references ends up being the same as eager_load. Like many things in Rails, you have a few ways of accomplishing the same result, and here you are witnessing that first hand. If I were writing them in a single statement, I would always prefer eager_load because it is more explicit and it is a single function call.
I would also prefer eager_load because I consider references a kind of hack. It says to the SQL generator "Hey, I am referring to this object in a way that you would not otherwise detect, so include it in the JOIN statement" and is generally used when you use a String to pass a SQL fragment as part of the query.
The only time I would use the includes(:associations).references(:associations) syntax is when it was an artifact needed to make the query work and not a statement of intent. The Rails Guide gives this good example:
Article.includes(:comments).where("comments.visible = true").references(:comments)
As for why referencing 1 association causes 3 to be JOIN'ed, I do not know for sure. The code for includes uses heuristics to decide when it is faster to use a JOIN and when it is faster to use 2 separate queries, the first to retrieve the parent and the second to retrieve the associated objects. I was surprised to find how often it is faster to use 2 separate queries. It may be that since the query has to use 1 join anyway, the algorithm figures it will be faster to use 1 big join rather than 3 queries, or it may in general think 1 join is faster than 4 queries.
I would not in general use preload unless I had a strong reason to believe that it was faster than join. I would just use includes alone and let the algorithm decide.

RoR/Squeel - How do I use Squeel::Nodes::Join/Predicates?

I just recently inherited a project where the previous developer used Squeel.
I've been studying Squeel for the past day now and know a bit about how to use it from what I could find online. The basic use of it is simple enough.
What I haven't been able to find online (except for on ruby-doc.org, which didn't give me much), is how to use Squeel::Nodes::Join and Squeel::Nodes::Predicate.
The only thing I've been able to find out is that they are nodes representing join associations / predicate expressions, which I had figured as much. What I still don't know is how to use them.
Can someone help me out or point me toward a good tutorial/guide?
I might as well answer this since I was able to figure out quite a bit through trial and error and by using ruby-doc as a guide. Everything I say here is not a final definition to each of these. It's just what I know that may be able to help someone out in the future in case anyone else is stuck making dynamic queries with Squeel.
Squeel::Nodes::Stub
Let's actually start with Squeel::Nodes::Stub. This is a Squeel object that can take either a symbol or a string and can convert it into the name of a table or column. So you can create a new Squeel::Nodes::Stube.new("value") or Squeel::Nodes::Stube.new(:value) and use this stub in other Squeel nodes. You'll see examples of it being used below.
Squeel::Nodes::Join
Squeel::Nodes::Join acts just like you might suspect. It is essentially a variable you can pass in to a Squeel joins{} that will then perform the join you want. You give it a stub (with a table name), and you can also give it another variable to change the type of join (I only know how to change it to outer join at the moment). You create one like so:
Squeel::Nodes::Join.new(Squeel::Nodes::Stub.new(:custom_fields), Arel::OuterJoin)
The stub is used to let the Join know we want to join the custom_fields table, and the Arel::OuterJoin is just to let the Join know we want to do an outer join. Again, you don't have to put a second parameter into Squeel::Nodes::Join.new(), and I think it will default to performing an inner join. You can then join this to a model:
Person.joins{Squeel::Nodes::Join.new(Squeel::Nodes::Stub.new(:custom_fields), Arel::OuterJoin)}
Squeel::Nodes::Predicate
Squeel::Nodes::Predicate may seem pretty obvious at this point. It's just a comparison. You give it a stub (with a column name), a method of comparison (you can find them all in the Predicates section on Squeel's github) and a value to compare with, like so:
Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value), :eq, 5)
You can even AND or OR two of them together pretty easily.
AND: Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value1), :eq, 5) & Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value2), :eq, 10)
OR: Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value1), :eq, 5) | Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value2), :eq, 10)
These will return either a Squeel::Nodes::And or a Squeel::Nodes::Or with the nested Squeel::Nodes::Predicates.
Then you can put it all together like this (of course you'd probably have the joins in a variable, a, and the predicates in a variable b, because you are doing this dynamically, otherwise you should probably be using regular Squeel instead of Squeel nodes):
Person.joins{Squeel::Nodes::Join.new(Squeel::Nodes::Stub.new(:custom_fields),
Arel::OuterJoin)}.where{Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value1), :eq, 5) | Squeel::Nodes::Predicate.new(Squeel::Nodes::Stub(:value2), :eq, 10)}
I unfortunately could not figure out how to do subqueries though :(

In Rails, does Eagerloading apply to the where condition on the query ? how do improve performance of the app, apart from using page caching?

I have three questions:
1)
file_or_folder and dataset each have many metainstances. Given the following query:
p= Metainstance.find(:first, :conditions=>["file_or_folder_id=? AND dataset_id=?", some.id, dataset_id],:include=>[:file_or_folder,:dataset])
Does eager loading apply on file_or_folder and dataset? Also, what is the best way of writing this query?
2) If I need to retrieve a huge amount of data, is it more efficient to write queries using joins or includes option or by using scopes.
3) I cannot use page caching, as I have dynamic content that keeps on changing. How else can I improve the performance of a Rails app?
1) First of all, find(:first) has been deprecated for a long time. It's actually finally going away in Rails 4. Here's how this query would look in the modern era (shamelessly copied from meagar's comment):
Metainstance.
where(:file_or_folder_id => some.id, :dataset_id => dataset_id).
includes(:file_or_folder, :dataset)
So, on to the question: Eager loading in this way means that the following will happen:
First, Rails will load the Metainstances that match the conditions of
the query.
Second, it will load all of the FileOrFolders that are associated
with the Metainstances fetched in the first query (not any others).
Finally, it will load all of the Datasets associated with those
Metainstances.
I think this means that the answer to your question is "Yes, eager loading applies the contents of the where clause."
2) I think we covered this with the above discussion of finder methods. I don't think they actually less efficient, per se. Just uglier and deprecated. The above code is the correct way to run a query like this.
3) There are literally entire books on improving Rails app performance. You're going to have to be much more specific about the query you're running and how you're using the results from it before anyone can give you meaningful advice on this.
a) Yes, it does perform eager loading. I would do this like
p= Metainstance.where(:file_or_folder_id => some.id, :dataset_id => dataset_id).includes([:file_or_folder, :dataset]).first
This also does eager loading.
b) If you are using file_or_folder and dataset later on, then it is best to use includes (and you avoid n+1 problem). If you are not using them and just need to join tables, then joins is the faster way.
c) There are many ways to improve performance of your application and you can find some of these methods in Scaling Rails Screencast series.

What's the difference between “includes” and “preload” in an ActiveRecord query?

I'm struggling to find a comparison of includes() and preload() for ActiveRecord objects. Can anyone explain the difference ?
Rails has 2 ways of avoiding the n+1 problem. One involves creating a big join based query to pull in your associations, the other involves making a separate query per association.
When you do includes rails decides which strategy to use for you. It defaults to the separate query approach (preloading) unless it thinks you are using the columns from the associations in you conditions or order. Since that only works with the joins approach it uses that instead.
Rails' heuristics sometimes get it wrong or you may have a specific reason for preferring one approach over the other. preload ( and its companion method eager_load) allow you to specify which strategy you want rails to use.
As apidoc said "This method is deprecated or moved on the latest stable version. The last existing version (v3.0.9) is shown here." So the difference is that includes just NOT deprecated.

why is Model.all different to Model.where('true') in rails 3

I have a query, which works fine:
ModelName.where('true')
I can chain this with other AR calls such as where, order etc. However when I use:
ModelName.all
I receive the "same" response but can't chain a where or order to it as it's an array rather than a AR collection.
Whereas I have no pragmatic problem using the first method it seems a bit ugly/unnecessary. Is there a cleaner way of doing this maybe a .to_active_record_collection or something?
There is an easy solution. Instead of using
ModelName.where('true')
Use:
ModelName.scoped
As you said:
ModelName.where('true').class #=> ActiveRecord::Relation
ModelName.all.class #=> Array
So you can make as many lazy loading as long as you don't use all, first or last which trigger the query.
It's important to catch these differences when you consider caching.
Still I can't understand what kind of situation could lead you to something like:
ModelName.all.where(foobar)
... Unless you need the whole bunch of assets for one purpose and get it loaded from the database and need a subset of it to other purposes. For this kind of situation, you'd need to use ruby's Array filtering methods.
Sidenote:
ModelName.all
should never be used, it's an anti-pattern since you don' control how many items you'll retrieve. And hopefully:
ModelName.limit(20).class #=> ActiveRecord::Relation
As you said, the latter returns an array of elements, while the former is an ActiveRecord::Relation. You can order and filter array using Ruby methods. For example, to sort by id you can call sort_by(&:id). To filter elements you can call select or reject. For ActiveRecord::Relation you can chain where or order to it, as you said.
The difference is where the sorting and processing goes. For Array, it is done by the application; for Relation - by the database. The latter is usually faster, when there is more records. It is also more memory efficient.

Resources