Ruby on Rails - Как объединить две таблицы? - PullRequest
1 голос
/ 19 декабря 2011

У меня есть две таблицы (темы и страницы) в отношениях один ко многим.Я хочу добавить критерии из тем и страниц для анализа 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 Ответ

4 голосов
/ 19 декабря 2011

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.Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...