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'])
Вопросы:
- результаты цепочки sql действительно возвращает две строки, но subject.size говорит только 1?
- Как мне сказать, чтобы он возвращал столбцы с: страниц?
- Почему subject.to_sql по-прежнему показывает только sql из оператора 1, почему он не включает цепочечный sql из оператора 2?
- По сути, что мне нужно написать операторы по-другому, чтобы проанализировать 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. Надеюсь это поможет!