Установка inverse_of на has_many: через рельсы 4.1

В документации подразумевается, что inverse_of будет работать для всего, кроме полиморфных ассоциаций. http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses

Однако он выглядит inverse_of все еще не работает для has_many: через

например. каждая комбинация, которую я пробовал для inverse_of в следующем примере, не работает.

class Event  < ActiveRecord::Base
  has_many :attendances
  has_many :users, through: :attendance
class User < ActiveRecord::Base
  has_many :attendances 
  has_many :events, through: :attendances
class Attendance < ActiveRecord::Base
  belongs_to :event
  belongs_to :user 

любые идеи этого должны работать? и если да, то как я бы установил inverse_of в этом примере?

UPDATE

например. из того, что я пробовал (также пытался на has_many: через)

class Event  < ActiveRecord::Base
  has_many :attendances , :inverse_of => :event
  has_many :users, through: :attendance
end
class User < ActiveRecord::Base
  has_many :attendances , :inverse_of => :user
  has_many :events, through: :attendances
end
class Attendance < ActiveRecord::Base
  belongs_to :event, :inverse_of => :attendances
  belongs_to :user,  :inverse_of => :attendances
end

также попробовал

class Event  < ActiveRecord::Base
  has_many :attendances  
  has_many :users, through: :attendance , :inverse_of => :events
end
class User < ActiveRecord::Base
  has_many :attendances 
  has_many :events, through: :attendances ,:inverse_of => :users
end
class Attendance < ActiveRecord::Base
  belongs_to :event
  belongs_to :user
end

Ответ 1

У меня был такой же вопрос в рельсах 4.1.6 (что я наткнулся на этот вопрос).

Потребовалось немного проб и ошибок (и перезагрузка сервера), но для меня работает следующее:

class User < ActiveRecord::Base
  has_many :company_users
  has_many :companies, through: :company_users
end

class Company < ActiveRecord::Base
  has_many :company_users
  has_many :users, through: :company_users
end

class CompanyUser < ActiveRecord::Base
  belongs_to :company, inverse_of: :company_users
  belongs_to :user, inverse_of: :company_users
end

Для ясности:

Схема

Пример:

user = User.last
company = user.companies.build( ... )
company.save
# ...
# SQL (0.9ms)  INSERT INTO "public"."company_users" ("company_id", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["company_id", 4], ["created_at", "2014-10-03 03:40:58.836975"], ["updated_at", "2014-10-03 03:40:58.836975"], ["user_id", 1]]
(1.6ms)  COMMIT
CompanyUser.last
<CompanyUser:0x00000020339710> {
        :id => 4,
:company_id => 4,
   :user_id => 1,
:created_at => Thu, 02 Oct 2014 20:40:58 PDT -07:00,
:updated_at => Thu, 02 Oct 2014 20:40:58 PDT -07:00
}

Поэтому в основном я устанавливаю inverse_of в модели соединения

Ответ 2

guides говорит, что inverse_of не поддерживается при использовании: through. В частности:


Есть несколько ограничений на поддержку inverse_of:

  • Они не работают с: через ассоциации.
  • Они не работают с: полиморфными ассоциациями.
  • Они не работают: как ассоциации.
  • Для ассоциаций belongs_to игнорируются обратные ассоциации has_many.

Ответ 3

Если вы просто используете ассемблер, сделайте

class Event  < ActiveRecord::Base
  has_many :attendances
  has_many :users, through: :attendances ## there must be  plural too
class User < ActiveRecord::Base
  has_many :attendances 
  has_many :events, through: :attendances
class Attendance < ActiveRecord::Base
  belongs_to :event
  belongs_to :user

Затем Event и User будут искать друг друга по модели Attendance (через event_id и user_id в таблице attendances в db). Чтобы увидеть подробности, см. реляционная ассоциация explian

Если вы хотите использовать ассоциацию inverse_of, это означает, что отношение будет привязано самим собой, а не третьей стороной. Сначала вы можете сделать:

class Event  < ActiveRecord::Base
  has_many :attendances
  has_many :users, :inverse_of => :events
class User < ActiveRecord::Base
  has_many :attendances 
  has_many :events, :inverse_of => :users
class Attendance < ActiveRecord::Base
  belongs_to :event
  belongs_to :user

Затем вам нужно изменить файл миграции следующим образом:

creata_table :events do |t|
  ....
  t.string, :user_id
end

creata_table :users do |t|
  ....
  t.string, :event_id
end

Подобно @event.users будет искать пользователей по user_id в модели пользователя напрямую, но не через модель посещаемости.

BTW, through не может использоваться вместе с inverse_of вместе, руководство Rails его ослабило.

Ответ 4

Функция inverse_of автоматически устанавливается с Rails 4.1 до тех пор, пока вы не используете class_name или foreign_key. В последней части этого видео о настройке моделей Rails 5 приведен пример того, как отношения has_many ведут себя без, а затем с inverse_of. Тест RSpec записывается, чтобы сначала показать, что object_ids разные, а затем после добавления inverse_of они заканчиваются одинаковыми:

https://www.youtube.com/watch?v=5sfufoY59Ek&feature=youtu.be&t=42m54s