为 has_many 处理 rails 中的关联...但是两个连接表很深 [英] Dealing with associations in rails for has_many through...but two join tables deep

查看:47
本文介绍了为 has_many 处理 rails 中的关联...但是两个连接表很深的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑 4. 在我的解释中有些东西是不正确的......附加的是一个(做得很差的图形),它显示了表格和模式是如何的,然后我的主要问题是我有什么提供者通过 provider_location 表通过组位置 id 加入,组位置保存组并最终保存组名称.这就是我想知道的,建立一个这样的表我如何获得组名?一直来自供应商.就像我需要通过 has_many 一样.(大注意:图中的提供者地址和组地址实际上是提供者位置和组位置)

Edit 4. Something in my explanation is just not going right... attached is a (very poorly done graphic) that shows the tables and how the schema is, and then my main question is given what I have that a provider is joined via a group location id via the provider_location table, which the group location holds the group and ultimately the group name. This is what I want to know, building a table like this how do I get to the group name? all the way from a provider. It is like I need a has_many through through. (BIG NOTE: Provider Address and Group Address in the image is really Provider Location and Group Location)

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

EDIT x 3: Thanks @mrshoco. It got me closer, now its like something else with my structure is not quite right.... I get this error when running 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

推荐答案

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

I've created a project which illustrates solution of your problem and it works. You can find it here https://github.com/dimakura/stackoverflow-projects/tree/master/32260679-dealing-with-associations. Below is description of the same concepts, so browsing the repository is completely optional.

实际上有两种方法可以解决您的问题,这两种方法都可以在适当的上下文中使用.

Actually there are two ways to solve your problem both of them are usable in appropriate context.

但让我们先创建表和模型.

But let's first create tables and models.

我简化了您的表格,省略了不相关的细节.下面是创建它们的脚本.

I simplified your tables, omitting irrelevant details. Below are scripts for creating them.

表:

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 模型之间的关系:

Models

Below are relations between Address, Group and GroupLocation models:

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.

You can see now, that from a given Provider you can easily navigate down to Groups.

现在让我们测试我们的设置.

Let's now test our setup.

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

We have definition of your problem in this request:

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

... how to get all the groups a provider might belong to through the provider locations through group locations...

正如我在开头所说,有两种方法可以解决您的问题,具体取决于所提供的内容.

As I said in the begining there are two ways to solve your problem, depending on what's given.

让我们首先假设我们选择了一个提供者,并且想要与这个提供者相关的所有组.

Let's first assume we have a provider selected and want all groups related to this single provider.

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

这是与单个提供商合作的好方法.

It's a great way when working with a single provider.

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

But there is another scenario, when we want to select all groups belonging to more than one provider. Even worse, we might be given request: "Give us all groups for providers whose age not exceeds 50".

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

In this case we can exploit direct joining.

下面我们举例说明,当我们想要为所有名字为 Shane 的提供者获取组时如何使用 join.

Below we illustrate, how to use joining when we want to get groups for all providers whose first name is 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

这篇关于为 has_many 处理 rails 中的关联...但是两个连接表很深的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆