Chris Muench
Chris Muench

Reputation: 18318

Ordering results in rails 3..It works like magic, but why?

class Course < ActiveRecord::Base
  belongs_to :course_category
  belongs_to :client
  belongs_to :user_created, :foreign_key => :user_created_by, :class_name => "User"
  belongs_to :user_updated, :foreign_key => :user_last_updated_by, :class_name => "User"
  has_many :course_steps, :dependent => :destroy
  has_many :steps, :through => :course_steps
  has_many :course_requests
end

Here is output from the rails console...

>> c=Course.first
=> #<Course id: 1, course_category_id: 1, client_id: 1, user_created_by: 1, user_last_updated_by: 1, title: "Test Course 1", summary: "", hidden: false, auto_register: false, created_at: "2011-03-08 01:03:47", updated_at: "2011-03-08 01:03:47">
>> c.course_steps
=> [#<CourseStep id: 3, step_id: 2, course_id: 1, position: nil, created_at: "2011-03-08 15:03:44", updated_at: "2011-03-08 15:03:44">, #<CourseStep id: 4, step_id: 3, course_id: 1, position: nil, created_at: "2011-03-08 15:03:46", updated_at: "2011-03-08 15:03:46">]
>> c.course_steps.order("id DESC")
=> [#<CourseStep id: 4, step_id: 3, course_id: 1, position: nil, created_at: "2011-03-08 15:03:46", updated_at: "2011-03-08 15:03:46">, #<CourseStep id: 3, step_id: 2, course_id: 1, position: nil, created_at: "2011-03-08 15:03:44", updated_at: "2011-03-08 15:03:44">]
>> c.course_steps.order("id DESC").to_sql
=> "SELECT \"course_steps\".* FROM \"course_steps\" WHERE (\"course_steps\".course_id = 1) ORDER BY id DESC"
>> c.course_steps.order("position DESC").to_sql
=> "SELECT \"course_steps\".* FROM \"course_steps\" WHERE (\"course_steps\".course_id = 1) ORDER BY position DESC"
>> c.steps.order("position DESC").to_sql
=> "SELECT \"steps\".* FROM \"steps\" INNER JOIN \"course_steps\" ON \"steps\".id = \"course_steps\".step_id WHERE ((\"course_steps\".course_id = 1)) ORDER BY position DESC"
>> c.steps.class
    => Array
    >> c.course_steps.class
    => Array
    >> 

The parts that I am confused by are: (I am glad they work, but I am just wondering why)

  1. The fact that I can call "order" on course_steps (which is an array) c.course_steps.order("id DESC")!?!?

  2. The fact that I can call c.steps.order("position DESC") when position is not even part of the steps table. It somehow does a magical join.

Upvotes: 0

Views: 463

Answers (1)

bassneck
bassneck

Reputation: 4043

The fact that I can call "order" on course_steps (which is an array) c.course_steps.order("id DESC")!?!?

As I see it, rails doesn't immediately query a database after each of the chained methods. Instead, it processes the whole chain and constructs the query. So order is not called on the course_steps array. It just appends an order part of the query.

Here's a qoute from the Beginning Rails:

Notice that when you call the order method, it returns an array object as you may have expected. One thing that happens on the background is that Active Record allows you to chain calls to multiple methods before sending the command to the database; so you can call all, followed by order, and some other methods we’ll talk about in the next chapter, to create more precise database queries. Also, Active Record is smart enough to use lazy loading, a practice that only hits the database when necessary—in this example, when you call the each method.

Upvotes: 1

Related Questions