0

This follows on from my previous question

I have a user model with two self joins, seller and buyer.

I have an categories model, a seller has_and_belongs_to_many categories, as does a buyer. How do I create the migration so I can do seller.categories and categories.buyers etc...

I thought it would be something like I have below but it doesn't work...

def change
    create_table :categories_sellers do |t|
      t.references :category
      t.references :user
    end
    add_foreign_key :categories_sellers, :users, column: :trainer_id
    add_index :categories_users, [:category_id, :seller_id]
    add_index :categories_users, :seller_id
    end
  end
Community
  • 1
  • 1
raphael_turtle
  • 7,154
  • 10
  • 55
  • 89
  • How are you hoping to categorize `sellers` and `buyers` in your join table? Surely you'd just need `user_id`, `category_id`? – Richard Peck Jan 12 '16 at 17:33
  • I thought I'd have two separate join tables one for sellers/categories and one for buyers/categories, I need to be able to find all sellers for a specific category, hence why I though a join table was right....no? – raphael_turtle Jan 12 '16 at 17:36
  • I know this doesn't answer your question, but it feels weird for a seller to belong to a category. Shouldn't a product rather belong to a category? – Mike Szyndel Jan 12 '16 at 17:49
  • the modeling could be simplified to make this problem easier to deal with using single-table inheritance (STI): http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html – clairity Mar 29 '17 at 23:45

1 Answers1

0

To answer your question, it looks like you just need to change t.references :user to t.references :seller.

That said, I would highly suggest modeling your project as such:

module User
  extend ActiveSupport::Concern

  has_many :category_users, as: :user
  has_many :categories, through: :category_users

  # include any common methods for buyers and sellers, 
  # basically your current User model
end

class Buyer < ActiveRecord::Base
  include User
end

class Seller < ActiveRecord::Base
  include User
end

class CategoryUser < ActiveRecord::Base
  belongs_to :category
  belongs_to :user, polymorphic: true
end

class Category < ActiveRecord::Base
  has_many :category_users
  has_many :buyers, through: :category_users, source: :user, source_type: 'Buyer'
  has_many :sellers, through: :category_users, source: :user, source_type: 'Seller'
end

I know that may require some changes that you didn't anticipate, but in doing that, you get more natural methods such as:

  • category.buyers
  • category.sellers
  • buyer.categories
  • seller.categories

Under the hood, your join table will have columns like:

  • id -- the row id
  • category_id -- the category id, of course
  • user_id -- the id of the Buyer or Seller
  • user_type -- one of "Buyer" or "Seller" (or any other type you deem as "user")

To run the migrations:

User doesn't need one, it's not a model.

Buyer and Seller are pretty straightforward, old User model + Buyer/Seller model.

Category doesn't need one as it already exists.

CategoryUser:

def change
  create_table :category_users do |t|
    t.references :category
    t.references :user, polymorphic: true
  end
  add_index :category_users, :category_id
  add_index :category_users, [:category_id, :user_id]
  add_index :category_users, [:category_id, :user_id, :user_type]
end

I haven't checked this personally but should be right, or close. The overall principle, though, is to make use of polymorphic associations to make a more natural association between "some kind of user" (whether it be a Buyer, Seller, or any other type of user you come up with) and a category. Then, you don't need to replicate the same sort of associations over and over again because the models slightly vary.

Here's more details on this approach:

http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

GoGoCarl
  • 2,519
  • 13
  • 16