Ruby on Rails - Как объединить две таблицы?

У меня есть две таблицы (темы и страницы) в отношениях один ко многим. Я хочу добавить критерии из тем и страниц для анализа SQL, но прогресс был очень медленным и часто сталкивался с проблемами. Я новенький в рельсах, пожалуйста, помогите.

class Subject < ActiveRecord::Base
  has_many :pages
end

class Page < ActiveRecord::Base
  belongs_to :subject 
end

Образцы данных по темам, перечисленные тремя колонками ниже:

id  name    level
1   'Math'  1
6   'Math'  2
...

Пример данных на страницах, перечисленных ниже столбцов:

id  name                    subject_id
--  --------------------    ----------
2   Addition                1
4   Subtraction             1
5   Simple Multiplication   6
6   Simple Division         6
7   Hard Multiplication     6
8   Hard Division           6
9   Elementary Divsion      1

Учитывая, что я не знаю subject.id, я знаю только название и уровень темы, а также имя страницы. Вот sql, который я хочу сгенерировать (или что-то подобное, что даст тот же результат):

select subjects.id, subjects.name, pages.id, pages.name from subjects, pages
 where subjects.id = pages.subject_id
   and subjects.name = 'Math'
   and subjects.level = '2'
   and pages.name like '%Division'  ;

Я ожидаю получить две строки в результате:

subjects.id     subjects.name   pages.id    pages.name 
-----------     -------------   --------    -----------
6               Math            6           Simple Division
6               Math            8           Hard Division

Это очень простой SQL, но я не смог получить желаемое в рельсах.

Here is my rails console:  

>> subject = Subject.where(:name => 'Math', :level => 2)
  Subject Load (0.4ms)  SELECT `subjects`.* FROM `subjects` WHERE `subjects`.`name` = 'Math' AND `subjects`.`level` = 2
[#<Subject id: 6, name: "Math", position: 1, visible: true, created_at: "2011-12-17 04:25:54", updated_at: "2011-12-17 04:25:54", level: 2>]
>> 
>> subject.joins(:pages).where(['pages.name LIKE ?', '%Division'])
  Subject Load (4.2ms)  SELECT `subjects`.* FROM `subjects` INNER JOIN `pages` ON `pages`.`subject_id` = `subjects`.`id` WHERE `subjects`.`name` = 'Math' AND `subjects`.`level` = 2 AND (pages.name LIKE '%Division')
[#<Subject id: 6, name: "Math", position: 1, visible: true, created_at: "2011-12-17 04:25:54", updated_at: "2011-12-17 04:25:54", level: 2>, #<Subject id: 6, name: "Math", position: 1, visible: true, created_at: "2011-12-17 04:25:54", updated_at: "2011-12-17 04:25:54", level: 2>]
>> 
>> subject.to_sql
"SELECT `subjects`.* FROM `subjects`  WHERE `subjects`.`name` = 'Math' AND `subjects`.`level` = 2"
>> subject.size
1
>> subject.class
ActiveRecord::Relation

1-е утверждение: subject = Subject.where(:name => 'Math',:level => 2) 2-е утверждение: subject.joins(:pages).where(['pages.name LIKE?', '%Division'])

Вопросы:

  1. результаты цепочки sql действительно возвращает две строки, но subject.size говорит только 1?
  2. Как мне сказать, чтобы он возвращал столбцы с: страниц?
  3. Почему subject.to_sql по-прежнему показывает только sql из оператора 1, почему он не включает цепочечный sql из оператора 2?
  4. По сути, что мне нужно написать операторы по-другому, чтобы проанализировать SQL, как указано выше (или достичь того же результата)?

Большое спасибо.

1 ответ

Решение

1) ActiveRecord сопоставит результаты вашего запроса с объектами, а не с произвольными возвращаемыми строками, так как вы основали создание запроса на Subject класс, он смотрит на ваши результирующие строки и выясняет, что он ссылается только на 1 уникальный Subject объект, поэтому возвращает только этот единственный Subject пример.

2) Данные столбца есть, но вы работаете против того, что ActiveRecord хочет дать вам, то есть объектов. Если вы предпочитаете, чтобы возвращались страницы, тогда вам нужно основывать создание запроса на Page учебный класс.

3) Вы не сохранили результаты добавления join(:pages)... обратно в subject переменная. Если вы сделали:

subject = subject.joins(:pages).where(['pages.name LIKE ?', '%Division'])

Вы получите полный запрос при запуске subject.to_sql

4) Чтобы получить объекты страницы, вы можете сделать что-то вроде этого, обратите внимание, что мы основываем это на Page учебный класс:

pages = Page.joins(:subject).where(['subjects.name = ? AND subjects.level = ? AND pages.name LIKE ?', 'Math', 2, '%Division'])

Затем получить доступ к имени субъекта оттуда для первого Page возвращенный объект:

pages[0].subject.name

Что, поскольку у вас есть объединение в первом, не приведет к другому запросу SQL. Надеюсь это поможет!

Другие вопросы по тегам