Jonnyx Delavilla
Jonnyx Delavilla

Reputation: 565

Rails ActiveRecord model association

I have a User model and a product model.

User has_many :products, :dependent => :destroy
Product belongs_to :user, :foreign_key => "user_id", touch: true

I want to create a wishlist for every user. So i have to create a wishlist model with proper association. But i don't know how to start. I presume that the wishlist model contain an id, user_id and product_id field

Do i have to use has_many through association or a has_and_belongs_to_many ? I also want that if a user is destroyed to destroy his wishlist.

What is the best way to do? Many thanks!

Upvotes: 0

Views: 611

Answers (3)

mjnissim
mjnissim

Reputation: 3112

To create your join table, do:

rails g migration create_products_users_table

Once you've done that, you need to add some code, below, to create the fields in the join table. Notice the :id => false, because you do not need an id in the join table:

class CreateProductsUsersTable < ActiveRecord::Migration
  def change
    create_table :products_users, :id => false do |t|
      t.references :product
      t.references :user
    end
    add_index :products_users, [:product_id, :user_id]
    add_index :products_users, :user_id
  end
end

The code above also creates some indexes and ensures that you don't have duplicates even at the database level.

Your models would then have to look like this:

class Product < ActiveRecord::Base
  has_and_belongs_to_many :users
end

class User < ActiveRecord::Base
  has_and_belongs_to_many :products
end

When you destroy a user correctly, like user.destroy and not just delete it (there is a difference), then the related rows in the join table will be deleted as well. This is built in to ActiveRecord.

Notice though, that doing this will not really let you use the join table. It will accept code like user.products = [product1, product2] etc, and other goodies, but no real use of a wish list.

If you do want to use a wish list, you will have to create and use the middle join table differently, using has_many :through (I didn't check PinnyM's answer but that might be the way to do it).

Upvotes: 0

PinnyM
PinnyM

Reputation: 35533

As @JZ11 pointed out, you shouldn't be linking a Product directly to a User (unless a User actually 'owns' a product for some reason). However, what was missed is the model that makes up a Wishlist item:

class User < ActiveRecord::Base
  has_many :wishlists       # or has_one, depending on how many lists a User can have...
end

class Product < ActiveRecord::Base
  has_many :wishlist_items
end

class Wishlist < ActiveRecord::Base
  belongs_to :user
  has_many :wishlist_items
  has_many :products, :through => :wishlist_items
end

class WishlistItem < ActiveRecord::Base
  belongs_to :product
  belongs_to :wishlist
end

Naturally, you should be adding :dependent => :destroy where necessary.

Upvotes: 1

jamesfzhang
jamesfzhang

Reputation: 4473

You don't need the has_many :products relationship on User. I don't think it makes sense for User and Product to be linked outside of a Wishlist.

class Wishlist < ActiveRecord::Base
  has_many :products
  belongs_to :user
end

class User < ActiveRecord::Base
  has_one :wishlist, dependent: :destroy
end

class Product < ActiveRecord::Base
  belongs_to :wishlist
end

Upvotes: 1

Related Questions