0

I previously created a joined table with the migration:

class CreateJoinTableCategoryListing < ActiveRecord::Migration[5.2]
  def change
    create_join_table :categories, :listings do |t|
      # t.index [:category_id, :listing_id]
      # t.index [:listing_id, :category_id]
    end
  end
end

I was looking back on this as i am going to be creating a new join tables. But while looking at it i noticed i migrated with the t.index's still commented out and the joined tables still operate correctly.

I read into this and i haven't found any posts about either someone doing the same or not needing them.

How is it operating with those index's never migrated and how needed are they?

I am creating a new migration:

class CreateJoinTable < ActiveRecord::Migration[5.2]
  def change
    create_join_table :users, :affiliates do |t|
      # t.index [:user_id, :affiliate_id]
      # t.index [:affiliate_id, :user_id]
    end
  end
end

Which index should i be choosing here?

How it should work is that an affiliate is able to manually submit a "commission" to the table (which does need to be added to the migration), but if the commission is updated, it should take the place of the column and not create a new row.

A user will have really nothing to do with this and will be mostly updated by the affiliate to update the commission rates they have on the user.

Update:

Is it even possible to add another field to the join table?

I wanted to add a :commission to the table but i can't find any docs to do anything for that. Should i just be defining the commission rate within the users table and do away with the join table?

UPDATE 2:

Ended up scratching this idea and keeping my current method of doing it with the users and affiliates association only. I did away with the UsersAffiliates idea as it's not needed for this case.

uno
  • 1,421
  • 12
  • 38
  • 1
    Indexes speed up the searching. So you can still search for specific record without them, but it's slower. – Marek Lipka Jan 09 '19 at 07:12
  • When looking at my join table in the database. It has listing_id and category_id. Do they just get automatically added? and also - should i create any new migrations to help this? – uno Jan 09 '19 at 07:14
  • Yes, the columns themselves are added automatically by `create_join_table` method, look here: https://www.rubydoc.info/github/rails/rails/ActiveRecord%2FConnectionAdapters%2FSchemaStatements:create_join_table Yes, to add the indexes that you need, you should probably create another migration. – Marek Lipka Jan 09 '19 at 07:17
  • Hm... ok i will update. I added the migration i need to do and confused on how i should go about choosing which one. I'm confused because they both seem the same essentially jjust in a different order. and the link you send me doesn't show the same style of the use of the array – uno Jan 09 '19 at 07:23
  • It depends on by which column you're planning to search this table (or maybe both of them). – Marek Lipka Jan 09 '19 at 07:25
  • It will be used for creating charges with something like @order.user.affiliate.commission ... that may be wrong - i haven't used a jointable for something like this yet but that's the idea and basically how i currently do it. I just realized i need to allow affiliates to update commission based on each user (client) so i need a join table unless i do it through the users table but that didn't seem appropriate – uno Jan 09 '19 at 07:28
  • But then again, an affiliate will be able to update it based on their users - but this is found through the users table. A user has_one :affiliate and affiliate belongs t user. Whats your thoughts? – uno Jan 09 '19 at 07:29
  • omg, well i had the wrong migration in the OP. I updated it . my bad – uno Jan 09 '19 at 07:36

1 Answers1

0

How is it operating with those index's never migrated and how needed are they?

All types of assocations in Rails will work without indices. The only thing that is required is that the correct tables and columns exist.

Indices are however critical for performance as the size of your database grows. They also provide constraints such as uniqueness that ensure that duplicate data cannot be inserted due to race conditions.

Which index should i be choosing here?

The whole reason that Rails generates two different indices is that you should choose the index that cooresponds to how you will most often be searching the table. If you are most often using User.joins(:affilitates) you would choose t.index [:user_id, :affiliate_id] for example.

How it should work is that an affiliate is able to manually submit a "commission" to the table (which does need to be added to the migration).

The create_join_table macro creates a join table named for has_and_belongs_to_many assocations.

The main problem with has_and_belongs_to_many assocations is that they are headless. There is no model and therefore no way to query the table directly or add additional metadata columns.

What you instead want is a has_many :through association.

class User < ApplicationRecord
  has_many :user_affiliates
  has_many :affiliates, through: :user_affiliates
end

class Affiliate < ApplicationRecord
  has_many :user_affiliates
  has_many :affiliates, through: :user_affiliates
end

# call this whatever you want
class UserAffiliate  < ApplicationRecord
  belongs_to :user
  belongs_to :affilitate
end

While has_and_belongs_to_many uses the table naming scheme users_affilities (plural_plural) you want to use user_affilities for a has_many through: association.

You can fix this by:

  1. Just generating the table/model through the normal generator rail g model user_affiliate.
  2. If the table exists write a migration to rename the table.

but if the commission is updated, it should take the place of the column and not create a new row.

You can solve this by:

  1. Add a unique compound index on the two columns t.index [:user_id, :affiliate_id], unique: true.
  2. Add a uniqueness validation in the join model. validates_uniqueness_of :user_id, scope: :affiliate_id.
  3. Use .find_or_initialize_by in your controller to update an existing row if it exists instead of creating a new row if one already exists.
max
  • 96,212
  • 14
  • 104
  • 165
  • Well, I read that you can't/shouldn't add columns to a jointable. I previously wanted to join users and affiliates and have a commission attribute within that same table - but apparently, and i could be wrong, you can't do that. As of now i just added the commission to the users table since commission will be dependent on a per user basis – uno Jan 09 '19 at 16:00
  • You either really misread something or should be more critical of cr*p you read. There are tons of valid cases where you want to attach additional data to a join table. There is nothing magical about them, its just a table with two foreign key columns. And it can be done - just not with has_and_belongs_to_many. – max Jan 09 '19 at 16:10
  • And adding the column to the users table is not the same thing at all. It will fix the value per user while the later is unique per combination. – max Jan 09 '19 at 16:12
  • You were right i created the joined table with the commission. But as for the users table doing it that way, I have an affilaite association already through an affiliate_id – uno Jan 09 '19 at 16:30
  • wow im an idiot. just read whta you wrote and i like it. going to give it a try. although, would this be much more beneficial than just having the commission in the users table and allowing an affiliate to update it that way? Will form input auotmatically generate records to the UserAffiliate table once submitted due to the associations? or is there controller needed? – uno Jan 09 '19 at 16:46
  • Hey so I am a bit perplexed on this. How would i input information, update, etc. into the Tables Database for the UserAffiliate without specifying the use of a controller? For example, 1, How would and affiliate_id and user_id become associated, just manually? and 2, when i have a User_id 1 associated with an Affiliate_id 1 in the UserAffiliate table, how would i then input and update the commission column in the Tables Database? Just looking for a piece of example code if possible? – uno Jan 10 '19 at 03:08
  • This are quite a few quite involved topics that I can't explain in few sentences. You might want to start by reading the [rails guides on associations](https://guides.rubyonrails.org/association_basics.html) thoroughly to understand how they actually work and then move on to how nested attributes work in rails. – max Jan 10 '19 at 04:27
  • TBH i was overthinking it. I already know how to apply this. Once i have the users model form with a nested UsersAffiliate model, i can just add the affiliate_id manually that way. – uno Jan 10 '19 at 05:21
  • I was trying this out today and using has_many in the users table didn't work and the server wouldn't start. i'm stuck rn: any chance you can take a took here: https://stackoverflow.com/questions/54138629/unpermitted-parameter-with-has-many-and-belongs-to-param-through-param – uno Jan 11 '19 at 03:20