处理rails中的关联为has_many通过…但是两个连接表深

编辑4.在我的解释中的一些东西是不正确的…附件是一个(非常糟糕的图形),显示表格和架构是如何,然后我的主要问题是我有什么提供者通过加入通过provider_location表的组位置ID,组位置保存组,最终保存组名。 这就是我想知道的,构建一个这样的表如何获得组名? 从提供者那里一路走来。 这就像我需要一个has_many贯穿。 (大注:图像中的提供商地址和组地址实际上是提供商位置和组位置)

粗糙的模型图。提供者可以在许多组位置拥有许多地址。通常,一个组有许多地址

编辑x 3:谢谢@mrshoco。 它让我更接近,现在它就像我的结构其他东西不太正确….我在运行provider_test_location.rb时遇到此错误

vagrant@precise32:/vagrant/ipanmv2$ rake test test/models/provider_location_tes t.rb Run options: --seed 18117 # Running: E Finished in 0.190900s, 5.2383 runs/s, 5.2383 assertions/s. 1) Error: ProviderLocationTest#test_fetching_a_group_name_for_a_provider: ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: provider_ locations.group_id: SELECT groups.group_name FROM "groups" INNER JOIN "provider_ locations" ON "provider_locations"."group_id" = "groups"."id" INNER JOIN "provid ers" ON "providers"."id" = "provider_locations"."provider_id" WHERE "providers". "first_name" = 'Shane' test/models/provider_location_test.rb:37:in `puts' test/models/provider_location_test.rb:37:in `puts' test/models/provider_location_test.rb:37:in `block in ' 1 runs, 1 assertions, 0 failures, 1 errors, 0 skips 

这是完整的unit testing

 require 'test_helper' class ProviderLocationTest < ActiveSupport::TestCase # test "the truth" do # assert true # end test "adding a provider to a group location" do group = Group.new group.group_name = 'My Awesome' group.save adr = Address.new adr.city = 'Las Cruces' adr.state = 'New Mexico' adr.zip = '88012' adr.address_line_one = '382 Dark side of moon' adr.address_line_two = '' adr.save gl = GroupLocation.new gl.group = group gl.address=adr gl.save prv = Provider.new prv.first_name = 'Shane' prv.last_name = 'Thomas' prv.save pl = ProviderLocation.new pl.provider = prv pl.group_location = gl ###############ISSUE assert pl.save, 'Provider location did not save' puts Group.joins(:providers).where(providers: { first_name: 'Shane' }).select('groups.group_name') end end 

模型如下:

 class Provider < ActiveRecord::Base belongs_to :designation belongs_to :specialty has_many :provider_locations has_many :invoices has_many :groups, through: :provider_locations end class ProviderLocation < ActiveRecord::Base belongs_to :provider belongs_to :group_location end class Group < ActiveRecord::Base #validations validates :group_name, presence: true #associations has_many :providers, through: :provider_locations has_many :invoices has_one :billing has_many :addresses, through: :group_locations has_many :group_locations belongs_to :billing_address, class_name: 'Address', foreign_key: 'billing_address_id' belongs_to :mailing_address, class_name: 'Address', foreign_key: 'mailing_address_id' has_and_belongs_to_many :insurances has_many :provider_locations end class GroupLocation < ActiveRecord::Base belongs_to :address belongs_to :group end class Address < ActiveRecord::Base has_many :group_locations has_many :billings end 

我已经创建了一个项目,它说明了问题的解决方案并且有效。 你可以在这里找到它https://github.com/dimakura/stackoverflow-projects/tree/master/32260679-dealing-with-associations 。 下面是相同概念的描述,因此浏览存储库是完全可选的。

实际上,有两种方法可以解决您的问题,它们都可以在适当的环境中使用。

但是我们首先创建表格和模型。

创建表格

我简化了你的表格,省略了不相关的细节。 以下是用于创建它们的脚本。

表:

 create_table :groups do |t| t.string :group_name t.timestamps null: false end 

地址表:

 create_table :addresses do |t| t.string :city t.string :state t.string :zip t.string :address_line_one t.string :address_line_two t.timestamps null: false end 

group_locations表:

 create_table :group_locations do |t| t.references :group, index: true, foreign_key: true t.references :address, index: true, foreign_key: true t.timestamps null: false end 

提供者表:

 create_table :providers do |t| t.string :first_name t.string :last_name t.timestamps null: false end 

provider_locations表:

 create_table :provider_locations do |t| t.references :provider, index: true, foreign_key: true t.references :group_location, index: true, foreign_key: true t.timestamps null: false end 

楷模

以下是AddressGroupGroupLocation模型之间的关系:

 class Address < ActiveRecord::Base has_many :group_locations end class Group < ActiveRecord::Base has_many :group_locations end class GroupLocation < ActiveRecord::Base belongs_to :group belongs_to :address has_many :provider_locations end 

ProviderLocation也很简单:

 class ProviderLocation < ActiveRecord::Base belongs_to :provider belongs_to :group_location end 

Provider相对复杂:

 class Provider < ActiveRecord::Base has_many :provider_locations has_many :group_locations, through: :provider_locations has_many :groups, through: :group_locations end 

您现在可以看到,从给定的Provider您可以轻松导航到Group

我们现在测试我们的设置。

测试

我们在此请求中定义了您的问题:

...如何通过组位置通过提供者位置获取提供者可能属于的所有组...

正如我在开始时所说,有两种方法可以解决您的问题,具体取决于给出的内容。

我们首先假设我们选择了一个提供商,并希望所有与此单一提供商相关的组。

 class ProviderLocationTest < ActiveSupport::TestCase def setup group = Group.create(group_name: 'My Awesome') adr = Address.create(city: 'Las Cruces', state: 'New Mexico', zip: '88012', address_line_one: '382 Dark Side of the Moon', address_line_two: '') gl =GroupLocation.create(group: group, address: adr) @provider = Provider.create(first_name: 'Shane', last_name: 'Thomas') pl = ProviderLocation.create(provider: @provider, group_location: gl) end test 'getting groups for a single provider' do assert_equal ['My Awesome'], @provider.groups.map{ |group| group.group_name } end end 

与单个提供商合作时,这是一种很好的方式。

但是,当我们想要选择属于多个提供者的所有组时,还有另一种情况。 更糟糕的是,我们可能会收到要求:“为年龄不超过50岁的医疗服务提供者提供所有服务。”

在这种情况下,我们可以利用直接加入。

下面我们举例说明如何在我们想要为名字为Shane的所有提供商获取组时使用加入。

 test 'getting groups based on arbitrary query' do group_names = Group.joins(group_locations: [ provider_locations: :provider]).where("providers.first_name=?", 'Shane').map{ |group| group.group_name } assert_equal ['My Awesome'], group_names end 

以前的答案是正确的

 Group.joins(:providers).where(providers: { first_name: 'Shane' }).select('groups.name') 

但是你有一个错误’没有这样的表groups_providers’,因为在Provider模型中有has_and_belongs_to_many :groups所以rails正在搜索providers_groups或groups_providers模型。 而不是你应该编写has_many :groups, through: :provider_locationsbelongs_to :group ProviderLocation模型中的belongs_to :group

 # Group name given a provider name Group.joins(:providers).where('providers.first_name' => 'Shane').select('groups.name') # address/location of the provider given the group name Provider.joins(:groups).where("groups.name" => "your_group_name").first.provider_locations.first 

让我试着理解,我看到它的方式你有5个表,其中三个表示模型:

  • 提供商
  • 地址

另外两个是连接表:

  • 供应商定位
  • 集团定位

如果我理解正确,你有这个,因为一个组有很多地址,提供者也是如此。 提供者也直接与组建立关系,因为它不受地址的影响,我认为你缺少的是groups_providers的连接表,这当然需要迁移来创建所述表。 在这种情况下,你会有一些排序:

 class Provider < ActiveRecord::Base has_many_and_belongs_to_many :groups end 

但是如果。 提供者和组之间的关系仅取决于地址,提供者和组之间的关系通过地址:

 class Provider < ActiveRecord::Base has_many :addresses has_many :groups, though: addresses end # This is not tested, just illustrating the idea. 

组,提供者和地址之间的关系也可能依赖于三个嵌入式中的两个的ID,在这种情况下,我想知道更多关于这种设计背后的原因。