Rails — как искать в консоли, где есть ассоциация has_one

Я пытаюсь понять, что мне нужно сделать, чтобы использовать ассоциации в своих представлениях. Что-то не так, когда ассоциация представляет собой отношение has_one.

У меня есть модели под названием Project и Package. Ассоциации таковы:

Project has_one :package

Package belongs_to :project

В консоли могу написать:

p = Project.where(id: 26) 

Это дает мне проект. Затем я пишу:

p.package 

Я ожидаю, что это даст мне соответствующий пакет. Вместо этого я получаю длинное сообщение об ошибке, которое начинается со следующих строк:

NoMethodError: undefined method `package' for #<Project::ActiveRecord_Relation:0x007fb275c17698>

Я не знаю, что означает это сообщение. Я особенно запутался, потому что могу написать:

p = Package.find_by(project_id:26)

Это дает мне правильный пакет.

p = Package.find_by(project_id:26)
  Package Load (1.8ms)  SELECT  "packages".* FROM "packages" WHERE "packages"."project_id" = $1 LIMIT 1  [["project_id", 26]]
 => #<Package id: 25, project_id: 26, created_at: "2016-08-18 23:16:06", updated_at: "2016-08-24 05:11:11", has_gallery: nil> 

Почему я не могу найти пакет, написав в консоли p.package?

Я видел это сообщение, но не понял суть происходящего.


person Mel    schedule 27.08.2016    source источник
comment
Как вы назвали свои внешние ключи и в какую таблицу вы их поместили   -  person Chris    schedule 27.08.2016
comment
@ Крис - что ты имеешь в виду? У проекта есть идентификатор, и, поскольку пакет принадлежит проекту, в таблице пакетов есть ключ project_id.   -  person Mel    schedule 27.08.2016


Ответы (1)


where возвращает массив связанных объектов (обычно используется с ассоциацией has_many). Если есть только один связанный объект, он все равно вернет его в массиве.

find_by генерирует LIMIT 1 в конце запроса SQL и возвращает только один экземпляр.

Вы не можете вызвать package для массива, так как массив ActiveRecord_Relation не имеет понятия об ассоциациях. Только Project объектов знают метод package. Вот почему Project.where(id: something).package не сработает, а Project.find_by(id: something).package сработает.

Если вы хотите вызвать package при использовании where, вам нужно выбрать объект (как и из любого другого массива) - Project.where(id: something).first.package - это вызовет package для первого элемента массива, который будет работать

person Kkulikovskis    schedule 27.08.2016
comment
Спасибо. Это сработало, чтобы получить пакет, но затем я хочу увидеть атрибут в таблице пакетов, выполнив: p.has_participants (has_participants — это атрибут в таблице пакетов), но я получаю: p.has_participants NoMethodError: undefined method `has_participants ' for #‹Project:0x007fe1751a0a78› Это несмотря на то, что предыдущий p.package дает мне запись, которая включает false в качестве ответа на has_participants. Как мне понять это? - person Mel; 27.08.2016
comment
@Mel, не могли бы вы обновить вопрос, указав код просмотра? Потому что из ошибки видно, что вы вызываете has_participants для объекта Project. - person Kkulikovskis; 27.08.2016
comment
@ Мел, нет проблем :) - person Kkulikovskis; 27.08.2016