简体   繁体   中英

Rails 4: Referral Model Associations

I am creating a referral model that will be able to link 2 clients, one that was referred and one that did the referring. I already have the client model, but am wondering the correct way to setup the referral model such that I can query:

Client.find(x).referrals
# returns all referrals where referrer has the client's id

Client.find(x).referred_by
# returns client that referred this client

Setting up two associations to the same table is one of the trickiest associations in ActiveRecord. The key is to setup different associations for each foreign key column.

So lets start with the join table:

# This is a Rails 5 migration - don't copy paste it
# You'll have to generate one for rails 4
class CreateReferrals < ActiveRecord::Migration[5.0]
  def change
    create_table :referrals do |t|
      t.belongs_to :referrer_id, foreign_key: false
      t.belongs_to :referred_id, foreign_key: false
      # Since the table for the foreign key cannot be automatically derived you need to add them manually
      add_foreign_key :referrals, :clients, column: :referrer_id
      add_foreign_key :referrals, :clients, column: :referred_id
      t.timestamps
    end
  end
end

Lets setup the associations on Referral:

class Referral < < ActiveRecord::Base
  belongs_to :referrer, class_name: 'Client'
  belongs_to :referred, class_name: 'Client'
end

Nothing to funky here yet. class_name: 'Client' tells ActiveRecord (AR) which table the association points to since it cannot be derived from the name of the assocation. Now lets create the inverse associations on Client:

class Client < ActiveRecord::Base
  has_many :referrals, class_name: 'Referral', 
    foreign_key: 'referrer_id'
  has_many :referrals_as_referred, class_name: 'Referral', 
    foreign_key: 'referred_id'
end

To add the associations to other clients that are referred or referrers to a client use an indirect assocation:

class Client < ActiveRecord::Base
  # ...
  # clients reffered by this client
  has_many :referred_clients, 
        through: :referrals,
        source: :referred
  has_many :referrers, 
        through: :referrals_as_referred,
        source: :referrer
end
  • through: :referrals tells AR to join through the assocation named :referrals .
  • source: :referred indicates the assocation on the join table to use.

You can use self association for this. On Client model, add referrals_id column. The association in Client model would be like this :

class Client < ActiveRecord::Base
  has_many :referrals, class_name: "Client", foreign_key: :referrals_id
  belongs_to :referred_by, class_name: "Client", foreign_key: :referrals_id
end

Consider you have these two records in tables.

[{  
   "id":1,
   "name":"Admin",
   "referrals_id": nil,
 },
 {  
   "id":2,
   "name":"Client",
   "referrals_id":1,
 }]

Now you can query for referrals will returns all referrals where referrer has the client's id

Client.find(1).referrals

This will generate a SQL like :

`SELECT "clients".* FROM "clients" WHERE "clients"."referrals_id" = ?  [["referrals_id", 1]]`

for referred_by will returns client that referred this client

Client.find(2).referred_by

This will generate SQL like:

SELECT  "clients".* FROM "clients" WHERE "clients"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]

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