Вот пример того, что у меня сейчас есть:
#app/models/company.rb
class Company < ApplicationRecord
has_one :platform
end
.
#app.models/platform.rb
class Platform < ApplicationRecord
has_and_belongs_to_many :companies
end
и у меня также есть миграция, которая создала объединенную таблицу для связи платформы с несколькими компаниями.
class CreateJoinTableCompanyPlatforms < ActiveRecord::Migration[5.1]
def change
create_join_table :companies, :platforms do |t|
t.index [:company_id, :platform_id]
t.index [:platform_id, :company_id]
end
end
end
Однако когда я перехожу к своему представлению и пытаюсь вызвать Company.first.platform
, я получаю следующую ошибку:
ActionView::Template::Error (Mysql2::Error: Unknown column 'platforms.company_id' in 'where clause': SELECT
platforms
.* FROMplatforms
WHEREplatforms
.company_id
= 1 LIMIT 1):
Есть ли проблема с моей таблицей соединений, или я не могу строить свои модели таким образом?
Если я поменяю свой has_one :platform
на has_and_belongs_to_many :platforms
, тогда он будет работать отлично, так что я должен чего-то упустить, или это может быть просто не лучший способ сделать это.
Моя причина использования has_one
заключалась в том, что каждый раз, когда я вызываю company
, я не хотел указывать company.platforms.first.name
, а предпочел бы просто использовать company.platform.name
, поскольку в любом случае у него должен быть только один.
has_and_belongs_to_many
предназначен для симметричного использования; Другими словами, если модель платформы использует его для указания на компанию, тогда модель компании должна использовать его для указания на платформу. Попытка связать его с другим типом ассоциации должна потерпеть неудачу и потерпела неудачу.
Если вы хотите, чтобы company.platform.name
работал, рассматривали ли вы связь с has_many
? Нравится:
class Company < ApplicationRecord
belongs_to :platform
end
class Platform < ApplicationRecord
has_many :companies
end
Для этого типа отношений не требуется таблица соединений. Вместо этого он использует столбец platform.company_id
, упомянутый в вашем сообщении об ошибке.
Рад это слышать! Стоит знать, что has_and_belongs_to_many
предназначен для связи "многие ко многим". Но если каждая компания связана только с одной платформой, а платформа связана с более чем одной компанией, то вместо этого это отношения «один ко многим». Наконец, has_one
задуман как взаимосвязь «один-к-одному», которая используется очень редко. Я чаще всего использую отношения «один ко многим».
Большое спасибо!! Очень признателен
О, и если это сработает для вас, пожалуйста, отметьте его как правильный ответ.
Попытайся:
rails g scaffold Platform name
rails g scaffold Company name platform:references
class Company < ApplicationRecord
belongs_to :platform, inverse_of: companies
end
class Platform < ApplicationRecord
has_many :companies, inverse_of: platform
end
Platform.create({name: 'pl47'})
Company.create({name: 'My Company', platform: Platform.first })
Company.create({name: 'Your Company', platform: Platform.first })
Company.first.platform
Company.first.platform.name
Platform.find(1).companies
Platform.find(1).companies.each do |company|
puts company.name
end
На самом деле это тоже очень интересно. Быстрый вопрос, есть ли преимущество в том, чтобы делать это таким образом, по сравнению с без использования inverse_of
(как и другой ответ)? Узнавайте что-то новое каждый день! :)
Из документации кажется, что опция: inverse_of - это метод, позволяющий избежать запросов SQL, а не их генерировать. Это подсказка ActiveRecord использовать уже загруженные данные вместо их повторной выборки через связь.
Огромное спасибо. Я попробовал первое решение, но очень ценю помощь в этом. Я обязательно сохраню это под рукой.
Хм, это очень интересный способ сделать это. Я не думал о том, чтобы сделать это таким образом, но думаю, что это действительно может сработать для меня. Я очень ценю это!