2503ICT: Relationships


Under construction!

The following relationship in the micropost app

To generate a Relationship model between users:

reails generate model Relationshp follower_id:integer followed_id:integer

For efficiency only, we might want to add indexes on each column of the relationships table:

class CreateRelationships < ActiveRecord::Migration
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps
    end
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true
  end
end

Each user may be a follower in many relationships:

class User < ActiveRecord::Base
  has_many :microposts, dependent: :destroy
  has_many :relationships, foreign_key: "follower_id", dependent: :destroy

  has_many :followed_users, through: :relationships, source: :followed 
  ...
end
Now, user.followed_users is an array of users that user is following.

We also need to asociate relationships with users:

class Relationship < ActiveRecord::Base
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
  validates :follower_id, presence: true
  validates :followed_id, presence: true
end

To represent a user's "followers", or "following users", we need to introduce a reverse relationship:

class User < ActiveRecord::Base
  ...
  has_many :reverse_relationships, foreign_key: "followed_id",
                                   class_name:  "Relationship",
                                   dependent:   :destroy
  has_many :followers, through: :reverse_relationships, source: :follower
  ...
end

A form on a user's profile page (@user) that allows the current user to follow that user might look like this:

<%= form_for(current_user.relationships.build(followed_id: @user.id)) do |f| %>
  <div><%= f.hidden_field :followed_id %></div>
  <%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>

More details are in Sections 11.1 and 11.2 of Hartl's Tutorial.

In some ways, all this is easier if you give explicit SQL queries that join the users-relationships-users table.

The bids relationship in an auction app

Here, the relationship bids is a many-many relationship between users and items.

rails generate model Bid bidder_id:integer item_id:integer amount:float

Each user has many bids; each item has many bids. Their models need to be extended accordingly, To associate a bid with a user and an item:

class Bid < ActiveRecord::Base
  belongs_to :bidder, class: "User"
  belongs_to :item
  validates :bidder_id, presence: true
  validates :item_id,   presence: true
  ...
end

To find the items that a user has bid on:

class User < ActiveRecord::Base
  ...
  has_many :bids, foreign_key: "bidder_id"
  has_many :bid_items, through: :bids, source: :item
  ...

Given a user u, we can then refer to u.bids and u.bid_items.

Model Item needs to be extended similarly, but using :reverse_bids to define the bidders (users) on a given item.

To be continued...

References