【问题标题】:Dealing with associations in rails for has_many through...but two join tables deep在rails中处理has_many的关联...但是两个连接表很深
【发布时间】:2023-03-22 04:48:01
【问题描述】:

编辑 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 <class:ProviderLocatio
nTest>'

1 runs, 1 assertions, 0 failures, 1 errors, 0 skips

这是完整的单元测试

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

【问题讨论】:

  • 希望我理解正确。下面是我对你的问题的回答。如果仍然缺少某些内容,请提供更多信息。我真的很想在这个问题上进行合作。

标签: ruby-on-rails ruby rails-activerecord


【解决方案1】:
# 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

【讨论】:

  • 给我一个错误'没有这样的表 groups_providers'
  • 您之前是否运行过迁移?你有 groups_providers 表吗?因为,我的查询将只加入组和提供者表。
  • 不,如果我更改关联,我认为我不必运行迁移。不,我没有组提供程序表,也就是说,它们通过另外两个连接表连接:Provider_Locations 和 Group_Locations
  • 这很奇怪。我正在加入 providers 和 groups 表,那为什么抱怨 groups_providers 表?!?请发布错误堆栈跟踪。我去看看。
【解决方案2】:

上一个答案是正确的

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 模型。取而代之的是,您应该在 ProviderLocation 模型中编写 has_many :groups, through: :provider_locationsbelongs_to :group

【讨论】:

  • 这确实改变了一些事情,在描述发生了什么的帖子中添加了一个编辑。
  • 您不需要删除belongs_to :group_location。你应该按照我之前的建议将has_many :groups, through: :group_locations 更改为belongs_to :group
  • 再次感谢。我做了所有的编辑,没有发现 providers_groups 表错误,并在我的 Group 模型中意识到我有一个拥有并且属于很多人,我把它拿出来了,所以现在上面是一个编辑,我得到的错误对我来说毫无意义。所有模型都更新到现在的样子。
  • 我应该补充一点,我上面编辑中的 klass 错误对我来说毫无意义,是 klass 吗?看起来我打错了,但这就是它的名字。 耸耸肩
  • 感谢 mrshoco。我更接近并学习了很多关于关联的知识,一些如何加入找不到 id(将错误添加到已发布)
【解决方案3】:

我创建了一个项目来说明您的问题的解决方案并且它有效。你可以在这里找到它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 轻松导航到Groups。

现在让我们测试一下我们的设置。

测试

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

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

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

让我们首先假设我们选择了一个提供者,并希望所有组都与该单个提供者相关。

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_test 中进行了设置,类似于此处的 def 设置,@group 存在全局,我尝试了:@ group.providers.first.first_name 不知道提供者是什么...
  • 您需要在 Group 中添加一些关联,以便轻松获取提供者。你也需要这方面的帮助吗?
  • 我想我明白了!伙计,你摇滚使用你在提供者中所做的事情我将它应用于组并在这里添加了关联:has_many :provider_locations,通过::group_locations 我已经有了这个 has_many :providers,通过::provider_locations 似乎工作!
【解决方案4】:

让我试着理解一下,在我看来,你有 5 个表,其中三个代表模型:

  • 提供者
  • 地址

另外两个是连接表:

  • 提供者位置
  • 组位置

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

class Provider < ActiveRecord::Base
  has_many_and_belongs_to_many :groups
end

如果。 provider和group的关系只依赖于address,provider和group的关系是通过address来实现的:

class Provider < ActiveRecord::Base
  has_many :addresses
  has_many :groups, though: addresses
end

# This is not tested, just illustrating the idea.

组、提供者和地址之间的关系也有可能依赖于三个嵌入中的两个的 id?在这种情况下,我想了解更多关于这种设计背后的推理。

【讨论】:

  • 提供者和组之间的关系取决于“组地址” 通常一个提供者对一个组来说会很长,但我需要它更细化,因为一个组可以有很多位置。所以在这种情况下,提供者确实属于一个组,但通过组位置。原因是一个组可能有也可能没有多个位置。提供者可能属于也可能不属于多个组。但是提供者将属于一个组,如果它属于,它将位于特定位置,但它可能在许多位置属于该组。无论如何,它仍然是该组的一部分。
  • 在这种情况下,在我看来,提供者地址“has_one”提供者(我知道这听起来很时髦)。因为如果提供者将始终属于特定位置的组。 Q1:提供者有很多组还是只有一个组? Q2:你说的可能属于“在很多地方的一个群体”是什么意思?它可以属于具有多个位置的组,还是可以属于基于不同位置的多个组?
  • 所以 provider_location 应该有一个 has_one ,即使我已经说过belongs_to 了?是的,提供者可以属于许多组。但粒度是多个组通过一个位置。 IE。提供者可以属于 A 组,但它位于 A 组的位置 1、2 和 5。同样,提供者也可以属于 B 组的位置 2 的 B 组。等等...还在 provider_address 中添加 has_one 提供者会给我一个错误关于不能写未知属性'provider_location_id'所以我认为id需要迁移来支持它?如果这也有帮助,我可以照原样发布我的架构吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多