Skip to content

Instantly share code, notes, and snippets.

@AlxGolubev
Last active April 7, 2017 17:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AlxGolubev/075c4471c7b6f2548bff to your computer and use it in GitHub Desktop.
Save AlxGolubev/075c4471c7b6f2548bff to your computer and use it in GitHub Desktop.
Способ загрузки ассоциаций при использовании find_by_sql

При выполнении сложных запросов, часто бывает необходимо выполнить предзагрузку данных об ассоциациях какой либо модели. Обычно сложные запросы выполняються через find_by_sql, например

Post.find_by_sql "SELECT p.name, c.author FROM posts p, comments c WHERE p.id = c.post_id"
> [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]

Чтобы при вывзове ассоциаций объектов избежать проблемы с select(n+1) запросами в Rails существует eager-loading, например:

@users = User.where(status: 'activated').includes(:posts)

Благодаря такой конструкции при вызове @users.first.posts не будет произведен еще один дополнительный запрос для подгрузки постов, но это не работает с find_by_sql, так как этот метод вернет массив, а не ActiveRecord::Relation объект.

Для того чтобы избежать select(n+1) в данном случае необзодимо использовать:

Rails 3

@users = User.find_by_sql(some_condition)
ActiveRecord::Associations::Preloader.new(@users, :posts).run

Rails 4

@users = User.find_by_sql(some_condition)
ActiveRecord::Associations::Preloader.new.preload(@users, :posts)

В качестве первого аргумента выступает массив записей, второго - желаемая ассоциация. Также существует возможность в качестве параметров передать массив ассоциаций или хещ с ассоциациями ассоциация, например:

@users = User.find_by_sql(some_condition)

#Array of associations
ActiveRecord::Associations::Preloader.new.preload(@users, %i(posts images))

#Hash to eager load associations of associations
ActiveRecord::Associations::Preloader.new.preload(@users, {posts: :comments})

#Or combination of array and hash
ActiveRecord::Associations::Preloader.new.preload(@users, [:images, { posts: :comments }])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment