Skip to content
  • eileencodes's avatar
    de6b4efa
    Add option to skip joins for associations. · de6b4efa
    eileencodes authored
    
    
    In a multiple database application, associations can't join across
    databases. When set, this option tells Rails to make 2 or more queries
    rather than using joins for associations.
    
    Set the option on a has many through association:
    
    ```ruby
    class Dog
      has_many :treats, through: :humans, disable_joins: true
      has_many :humans
    end
    ```
    
    Then instead of generating join SQL, two queries are used for `@dog.treats`:
    
    ```
    SELECT "humans"."id" FROM "humans" WHERE "humans"."dog_id" = ?  [["dog_id", 1]]
    SELECT "treats".* FROM "treats" WHERE "treats"."human_id" IN (?, ?, ?)  [["human_id", 1], ["human_id", 2], ["human_id", 3]]
    ```
    
    This code is extracted from a gem we use internally at GitHub which
    means the implementation here is used in production daily and isn't
    experimental.
    
    I often get the question "why can't Rails do this automatically" so I
    figured I'd include the answer in the commit. Rails can't do this
    automatically because associations are lazily loaded. `dog.treats` needs
    to load `Dog`, then `Human` and then `Treats`. When `dog.treats` is
    called Rails pre-generates the SQL that will be run and puts that
    information into a reflection object. Because the SQL parts are pre-generated,
    as soon as `dog.treats` is loaded it's too late to skip a join. The join
    is already available on the object and that join is what's run to load
    `treats` from `dog` through `humans`. I think the only way to avoid setting
    an option on the association is to rewrite how and when the SQL is
    generated for associations which is a large undertaking. Basically the
    way that Active Record associations are designed, it is currently
    impossible to have Rails figure out to not join (loading the association
    will cause the join to occur, and that join will raise an error if the
    models don't live in the same db).
    
    The original implementation was written by me and Aaron. Lee helped port
    over tests, and I refactored the extraction to better match Rails style.
    
    Co-authored-by: default avatarLee Quarella <leequarella@gmail.com>
    Co-authored-by: default avatarAaron Patterson <aaron@rubyonrails.org>
    de6b4efa
    Add option to skip joins for associations.
    eileencodes authored
    
    
    In a multiple database application, associations can't join across
    databases. When set, this option tells Rails to make 2 or more queries
    rather than using joins for associations.
    
    Set the option on a has many through association:
    
    ```ruby
    class Dog
      has_many :treats, through: :humans, disable_joins: true
      has_many :humans
    end
    ```
    
    Then instead of generating join SQL, two queries are used for `@dog.treats`:
    
    ```
    SELECT "humans"."id" FROM "humans" WHERE "humans"."dog_id" = ?  [["dog_id", 1]]
    SELECT "treats".* FROM "treats" WHERE "treats"."human_id" IN (?, ?, ?)  [["human_id", 1], ["human_id", 2], ["human_id", 3]]
    ```
    
    This code is extracted from a gem we use internally at GitHub which
    means the implementation here is used in production daily and isn't
    experimental.
    
    I often get the question "why can't Rails do this automatically" so I
    figured I'd include the answer in the commit. Rails can't do this
    automatically because associations are lazily loaded. `dog.treats` needs
    to load `Dog`, then `Human` and then `Treats`. When `dog.treats` is
    called Rails pre-generates the SQL that will be run and puts that
    information into a reflection object. Because the SQL parts are pre-generated,
    as soon as `dog.treats` is loaded it's too late to skip a join. The join
    is already available on the object and that join is what's run to load
    `treats` from `dog` through `humans`. I think the only way to avoid setting
    an option on the association is to rewrite how and when the SQL is
    generated for associations which is a large undertaking. Basically the
    way that Active Record associations are designed, it is currently
    impossible to have Rails figure out to not join (loading the association
    will cause the join to occur, and that join will raise an error if the
    models don't live in the same db).
    
    The original implementation was written by me and Aaron. Lee helped port
    over tests, and I refactored the extraction to better match Rails style.
    
    Co-authored-by: default avatarLee Quarella <leequarella@gmail.com>
    Co-authored-by: default avatarAaron Patterson <aaron@rubyonrails.org>
Loading