Gibson
Gibson

Reputation: 2085

Should I use a has_and_belongs_to_many relation?

I'm trying to implement sponsored photos, so I have my photos table and my sponsors table.

Sponsor will have many photos, and photos will have many sponsors.

Should I use a has_and_belongs_to_many relation in both of the models?

In that case,

1.) Should I create a join intermediate table manually or Rails will do It automatically?

2.) Should I add photo_id to sponsors and sponsor_id to photos ?

Thanks guys

Upvotes: 1

Views: 423

Answers (3)

Richard Peck
Richard Peck

Reputation: 76784

Sounds like you'll benefit from has_and_belongs_to_many - if you don't want to include any specific information in the join table. I'll give you information on has_many :through to give you an overview of both approaches


HABTM

has_and_belongs_to_many is used if you just want to associate two tables.

It's "dumb" in that it doesn't rely on primary keys - only housing two foreign_key columns in the data-table. It's for this reason that you cannot include any specific information in the join model:

enter image description here

This means that if you want to use has_and_belongs_to_many, you'll be able to do this:

#app/models/sponsor.rb
class Sponsors < ActiveRecord::Base
   has_and_belongs_to_many :photos
end

#app/models/photo.rb
class Photo < ActiveRecord::Base
   has_and_belongs_to_many :sponsors
end

You'll then need to create a join table, with the name [plural_alphabetical_model]_[plural_alphabetical_model]

$ rails g migration CreatePhotosSponsors

#db/migrate/create_photos_sponsors.rb
class CreatePhotosSponsors < ActiveRecord::Migration
  def self.up
    create_table :photo_sponsors, :id => false do |t|
        t.references :photo
        t.references :sponsor
    end
    add_index :photos_sponsors, [:photo_id, :sponsor_id]
    add_index :photos_sponsors, :sponsor_id
  end

  def self.down
    drop_table :photos_students
  end
end

has_many :through

An alternative to the HABTM method is the has_many :through association. If you wanted to add specific information to your join data, you'll want to use this association. Reason being that it has a primary_key in the data table (and so can reference individual records):

enter image description here

#app/models/student.rb
class Student < ActiveRecord::Base
   has_many :sponsor_photos
   has_many :photos, through: :sponsor_photos
end

#app/models/sponsor_photo.rb
class SponsorPhoto < ActiveRecord::Base
   belongs_to :sponsor
   belongs_to :photo
end

#app/models/photo.rb
class Photo < ActiveRecord::Base
   has_many :sponsor_photos
   has_many :sponsors, through: :sponsor_photos
end

The beauty of this association is that you can include specific information in the join model, such as the price paid, or their expiry date

Upvotes: 3

Mohammad AbuShady
Mohammad AbuShady

Reputation: 42919

First the habtm relation, quoting from 'rails 4 way'

7.5.1 has_and_belongs_to_many
Before proceeding with this section, I must clear my conscience by stating that has_and_belongs_to_many is practically obsolete in the minds of many Rails developers, including the authors of this book. Use has_many :through instead and your life should be a lot easier.

generate a joining model SponsorPhoto for example, with photo_id and sponsor_id

class Sponsor < ActiveRecord::Base
  has_many :photos, through: :sponsor_photos
end

class Photo < ActiveRecord::Base
  has many :sponsors, through :sponsor_photos
end

class SponsorPhoto < ActiveRecord::Base
  belongs_to :sponsors
  belongs_to :photos
end

Upvotes: 2

Milind
Milind

Reputation: 5112

in this case,The has_many :through Association will work great

sponsor.rb    
 has_many :sponsor_photos, :dependent => :destroy
 has_many :photos, :through => :sponsor_photos


photo.rb
has_many :sponsor_photos, :dependent => :destroy
has_many :sponsors, :through => :sponsor_photos

sponsor_photo.rb
##holding only sponsor_id and photo_id
  belongs_to :sponsor
  belongs_to :photo


###########so now you can use################

@sponsor=Sponsor.first
##get all photos of a  sponsor
@sponsor.photos
@photo=Photo.first
##get all sponsors from a photo
@photo.sponsors

HOPE THIS HELPS...

Upvotes: 2

Related Questions