1

I have 2 models in my rails app, one with an UUID primary key :

class User < ActiveRecord::Base
  belongs_to :country, :foreign_key => 'country_uuid'
end

class Country < ActiveRecord::Base
  set_primary_key :uuid
  has_many :users
end

When I try something like that:

<% @user = User.find :first, :include => [:country] %>
<%= @user.country.name %>

I have the good result, but I see 2 requests in the log file. Why eager loading is not working when we change the ID key for UUID key ?

User Load (0.4ms)  SELECT `users`.* FROM `users` LIMIT 1
Country Load (0.4ms)  SELECT `countries`.* FROM `countries` WHERE (`countries`.`uuid` = '1')

And I would have something like:

User Load (0.4ms)  SELECT `users`.* FROM `users` INNER JOIN countries ON countries.uuid = users.country_uuid LIMIT 1

Is there a workaround ? If I change uuid key for id key, but keep the string format to store an uuid, will it be ok ?

Thanks,

alex.bour
  • 2,842
  • 9
  • 40
  • 66

1 Answers1

3

Use joins instead of include to get the inner join

includes always issues a 2nd query but not n+1 queries (lazy)

for the direction you are going in user -> 1 country it is not so important

but if you were going the other direction country -> many users

country = Country.first
# => select countries.* from countries where id = xxxx limit 1;
country.users.each do 
    # select users.* from users where user_id = xxxx;
    # this could be bad because of lazy loading, one query per iteration
end

# vs...
country = Country.first.includes(:users)
# => select countries.* from countries where id = xxxx limit 1;
# => select users.* from users where country_uuid IN (xxxx);
country.users.each do
    # users are all in memory
end

see http://guides.rubyonrails.org/active_record_querying.html for more info

I don't think the fact you are using UUID should make any difference

house9
  • 20,359
  • 8
  • 55
  • 61
  • Thanks. In fact, I tried with many users and it's ok: I have 2 queries for X users. <% @users = User.find :all, :include => [:country] %> <% @users.each do |user| %> <%= user.country.name %> <% end %> User Load (0.5ms) SELECT `users`.* FROM `users` Country Load (0.5ms) SELECT `countries`.* FROM `countries` WHERE (`countries`.`uuid` IN ('1','2')) – alex.bour Dec 16 '11 at 16:39