Недавно я читал больше о разнице между :joins
и :includes
в рельсах. Вот объяснение того, что я понял (с примерами:))
Рассмотрим этот сценарий:
Пользователь имеет_ множество комментариев и комментарий принадлежит_ пользователю.
Модель пользователя имеет следующие атрибуты: Имя (строка), Возраст (целое число). Модель Comment имеет следующие атрибуты: Content, user_id. Для комментария user_id может быть нулевым.
Присоединяется:
: объединения выполняют внутреннее соединение между двумя таблицами. Таким образом
Comment.joins(:user)
#=> <ActiveRecord::Relation [#<Comment id: 1, content: "Hi I am Aaditi.This is my first comment!", user_id: 1, created_at: "2014-11-12 18:29:24", updated_at: "2014-11-12 18:29:24">,
#<Comment id: 2, content: "Hi I am Ankita.This is my first comment!", user_id: 2, created_at: "2014-11-12 18:29:29", updated_at: "2014-11-12 18:29:29">,
#<Comment id: 3, content: "Hi I am John.This is my first comment!", user_id: 3, created_at: "2014-11-12 18:30:25", updated_at: "2014-11-12 18:30:25">]>
извлечет всех записей, где user_id (таблицы комментариев) равен user.id (таблица пользователей). Таким образом, если вы сделаете
Comment.joins(:user).where("comments.user_id is null")
#=> <ActiveRecord::Relation []>
Вы получите пустой массив, как показано.
Кроме того, объединения не загружают объединенную таблицу в память. Таким образом, если вы делаете
comment_1 = Comment.joins(:user).first
comment_1.user.age
#=>←[1m←[36mUser Load (0.0ms)←[0m ←[1mSELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1←[0m [["id", 1]]
#=> 24
Как видите, comment_1.user.age
снова запустит запрос к базе данных в фоновом режиме, чтобы получить результаты
Включает в себя:
: включает выполнение левого внешнего соединения между двумя таблицами. Таким образом
Comment.includes(:user)
#=><ActiveRecord::Relation [#<Comment id: 1, content: "Hi I am Aaditi.This is my first comment!", user_id: 1, created_at: "2014-11-12 18:29:24", updated_at: "2014-11-12 18:29:24">,
#<Comment id: 2, content: "Hi I am Ankita.This is my first comment!", user_id: 2, created_at: "2014-11-12 18:29:29", updated_at: "2014-11-12 18:29:29">,
#<Comment id: 3, content: "Hi I am John.This is my first comment!", user_id: 3, created_at: "2014-11-12 18:30:25", updated_at: "2014-11-12 18:30:25">,
#<Comment id: 4, content: "Hi This is an anonymous comment!", user_id: nil, created_at: "2014-11-12 18:31:02", updated_at: "2014-11-12 18:31:02">]>
приведет к объединенной таблице со всеми записями из таблицы комментариев. Таким образом, если вы сделаете
Comment.includes(:user).where("comment.user_id is null")
#=> #<ActiveRecord::Relation [#<Comment id: 4, content: "Hi This is an anonymous comment!", user_id: nil, created_at: "2014-11-12 18:31:02", updated_at: "2014-11-12 18:31:02">]>
будет извлекать записи, где comments.user_id равен nil, как показано.
Более того, включает в себя загружает обе таблицы в памяти. Таким образом, если вы делаете
comment_1 = Comment.includes(:user).first
comment_1.user.age
#=> 24
Как вы можете заметить, comment_1.user.age просто загружает результат из памяти, не отправляя запрос к базе данных в фоновом режиме.