简体   繁体   中英

Multiple has_one / belongs_to associations

Rails 5 - I have band and venue models. I have a common model that I want to use for info that is common between the band and model. I can't seem to get the relationships right.

Band.rb

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

band schema

  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

common Schema. Note - no key for the association with band. I'm pretty sure that I have that wrong.

  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

I thought that the common_id would go in the bands model but apparently I'm wrong.

I don't have any foreign keys in the common model.

How do I set up my models so that I can have :

Band -- Common

Venue -- Common

If I put a foreign key of band_id in the common model, what happens when I try to do the same association with venues. Do I add a venue_id to the common model?

Yes, you need to add venue_id and band_id in the common table. Common entity will have multiple belongs_to (ie belongs_to: Band & belongs_to: venue)

cascading will be done from the Band and Venue side as belongs_to exist in the Common entity and it's many_to_one/one_to_one relationship.

All i can see is that you need a many to many relation as a band can play at any number of venues and venue can host any number of bands so something like

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

and yes you need to have band_id and venue_id in common model and I would say you can even name your common model as Event as its more of a real world entity.

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 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM