多个has_one / belongs_to关联

时间:2018-06-05 04:13:59

标签: ruby-on-rails

Rails 5 - 我有乐队和场地模特。我有一个共同的模型,我想用于乐队和模型之间的共同信息。我似乎无法正确地建立关系。

Band.rb

class Band < ApplicationRecord
    has_one :common
    accepts_nested_attributes_for :common, allow_destroy: true
end

乐队架构

  create_table "bands", force: :cascade do |t|
    t.integer "user_id"
    t.integer "plan_id"
    t.string "band_name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "common_id"
    t.index ["common_id"], name: "index_bands_on_common_id"
  end

common.rb

class Common < ApplicationRecord
  belongs_to :band
end

常见架构。注意 - 与band关联没有关键。我很确定我有错。

  create_table "commons", force: :cascade do |t|
    t.integer "user_id"
    t.integer "plan_id"
    t.string "name"
    t.string "address1"
    t.string "address2"
    t.string "city"
    t.string "state"
    t.string "zip"
    t.string "website"
    t.string "phone1"
    t.string "phone1_note"
    t.string "phone2"
    t.string "phone2_note"
    t.string "short_description"
    t.text "long_description"
    t.integer "main_photo_id"
    t.boolean "payment_current"
    t.decimal "lat"
    t.decimal "lon"
    t.text "admin_notes"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

我认为common_id会出现在乐队模型中,但显然我错了。

我在普通模型中没有任何外键。

如何设置模型以便我可以:

乐队 - 普通

地点 - 共同

如果我将band_id的外键放在普通模型中,当我尝试与场地进行相同的关联时会发生什么。我是否在常见模型中添加了venue_id?

3 个答案:

答案 0 :(得分:1)

是的,您需要在公共表中添加venue_id和band_id。公共实体将具有多个belongs_to(即belongs_to:Band&amp; belongs_to:venue)

级联将从Band和Venue方面完成,因为belongs_to存在于Common实体中,并且它是many_to_one / one_to_one关系。

答案 1 :(得分:1)

所有我能看到的是,你需要一个多对多的关系,因为一个乐队可以在任意数量的场地播放,场地可以容纳任意数量的乐队,所以像

class Band < ApplicationRecord
    has_many :common - make sure you handle the plural
    has_many :venues, through: :common
end

class Venue < ApplicationRecord
    has_many :common - make sure you handle the plural
    has_many :bands, through: :common
end

class Common < ApplicationRecord
    belongs_to :band
    belongs_to :venue
end

是的,你需要在普通模型中使用band_id和venue_id,我会说你甚至可以将你的共同模型命名为Event,因为它更像是一个真实世界的实体。

答案 2 :(得分:1)

You should probably use a polymorphic association.

So, Common (bad name, IMO) might look like:

# == Schema Information
#
# Table name: commons
#
#  id                 :integer          not null, primary key
#  commonable_id      :integer 
#  commonable_type    :string
#  ... other stuff ...
#  created_at         :datetime         not null
#  updated_at         :datetime         not null
#
class Common < ApplicationRecord
  belongs_to :commonable, polymorphic: true 
  ... other stuff ...
end

Notice that you'll have commonable_type and commonable_id, which is what allows for the polymorphism.

Then, Band might look like:

class Band < ApplicationRecord
  has_one :common, as: :commonable
  ... other stuff ...
end

Similarly, Venue might look like:

class Venue < ApplicationRecord
  has_one :common, as: :commonable
  ... other stuff ...
end

Which will let you do:

@venue.common
@band.common

BTW, Common seems like a mash up of at least a couple of candidate classes, namely PhysicalAddress and PhoneNumber.

So, you might have something like:

# == Schema Information
#
# Table name: phone_numbers
#
#  id                 :integer          not null, primary key
#  phoneable_id       :integer 
#  phoneable_type     :string
#  number             :string
#  note               :string
#  created_at         :datetime         not null
#  updated_at         :datetime         not null
#
class PhoneNumber < ApplicationRecord
  belongs_to :phoneable, polymorphic: true
end

And

# == Schema Information
#
# Table name: physical_addresses
#
#  id                           :integer          not null, primary key
#  physical_addressable_id      :integer 
#  physical_addressable_type    :string
#  address1                     :string
#  address2                     :string
#  city                         :string
#  state                        :string
#  zip                          :string
#  created_at                   :datetime         not null
#  updated_at                   :datetime         not null
#
class PhysicalAddress < ApplicationRecord
  belongs_to :physical_addressable, polymorphic: true
end

And then do:

class Band < ApplicationRecord
  has_one :common, as: :commonable
  has_one :physical_address, as: :physical_addressable
  has_one :phone1, as: :phoneable, class_name: 'PhoneNumber'
  has_one :phone2, as: :phoneable, class_name: 'PhoneNumber'
end

You'll need that class_name since rails won't be able to infer the class name (PhoneNumber) from the association name (phone1 and phone2).