Я работаю с довольно простым has_many через: ситуация, когда я могу заставить параметры class_name/foreign_key работать в одном направлении, но не в другом. Возможно, вы можете мне помочь. (p.s. Я использую Rails 4, если это делает diff):
Русский: Пользователь управляет многими листингами через ЛистингManager, а листинг управляется многими пользователями через ЛистингManager. Диспетчер листинга имеет несколько полей данных, не связанных с этим вопросом, поэтому я отредактировал их в приведенном ниже коде
Здесь простую часть, которая работает:
class User < ActiveRecord::Base
has_many :listing_managers
has_many :listings, through: :listing_managers
end
class Listing < ActiveRecord::Base
has_many :listing_managers
has_many :managers, through: :listing_managers, class_name: "User", foreign_key: "manager_id"
end
class ListingManager < ActiveRecord::Base
belongs_to :listing
belongs_to :manager, class_name:"User"
attr_accessible :listing_id, :manager_id
end
как вы можете догадаться, таблица ListManager выглядит так:
create_table "listing_managers", force: true do |t|
t.integer "listing_id"
t.integer "manager_id"
end
поэтому единственным непростым здесь является то, что ListManager использует manager_id
, а не user_id
В любом случае, вышеизложенное работает. Я могу позвонить user.listings
, чтобы получить списки, связанные с пользователем, и я могу позвонить listing.managers
, чтобы получить менеджеров, связанных с листингом.
Однако (и здесь вопрос), я решил, что было бы не очень важно сказать user.listings
, так как пользователь может также "владеть", а не "управлять" списками, чего я действительно хотел: user.managed_listings
, поэтому я исправил user.rb
изменить has_many: списки через:: listing_managers
в has_many: managed_listings через:: listing_managers, class_name: "Listing", foreign_key: "listing_id"
Это точная аналогия с кодом в listing.rb
выше, поэтому я подумал, что это должно сработать сразу. Вместо этого мой rspec тест этого barfs, говоря
ActiveRecord::HasManyThroughSourceAssociationNotFoundError:
Could not find the source association(s) :managed_listing or :managed_listings in model ListingManager. Try 'has_many :managed_listings, :through => :listing_managers, :source => <name>'. Is it one of :listing or :manager?
:
it "manages many managed_listings" do
user = FactoryGirl.build(:user)
l1 = FactoryGirl.build(:listing)
l2 = FactoryGirl.build(:listing)
user.managed_listings << l1
user.managed_listings << l2
expect( @user.managed_listings.size ).to eq 2
end
Теперь я уверен, что ничего не знаю. Да, я думаю, я мог бы сделать псевдоним, но я обеспокоен тем, что тот же метод, используемый в listing.rb
, не работает в user.rb
. Не могли бы вы объяснить?
UPDATE: Я обновил код, чтобы отразить предложения @gregates, но у меня все еще возникает проблема: я написал дополнительный тест, который терпит неудачу (и подтвержден "рукой" - в консоли Rails). Когда вы пишете тест следующим образом:
it "manages many managed_listings" do
l1 = FactoryGirl.create(:listing)
@user = User.last
ListingManager.destroy_all
@before_count = ListingManager.count
expect( @before_count ).to eq 0
lm = FactoryGirl.create(:listing_manager, manager_id: @user.id, listing_id: l1.id)
expect( @user.managed_listings.count ).to eq 1
end
Вышеуказанное не выполняется. Rails генерирует ошибку PG::UndefinedColumn: ERROR: column listing_managers.user_id does not exist
(она должна искать "listing_managers.manager_id" ). Поэтому я думаю, что на стороне пользователя ассоциации все еще есть ошибка. В user.rb
has_many :managed_listings, through: :listing_managers, source: :listing
, как пользователь знает, использовать manager_id
для доступа к его листингам?