Skip to content

Instantly share code, notes, and snippets.

@jcquarto
Last active December 20, 2015 21:28
Show Gist options
  • Save jcquarto/6197313 to your computer and use it in GitHub Desktop.
Save jcquarto/6197313 to your computer and use it in GitHub Desktop.
has_many through consistently causes me to re-think what it all means. Here's a useful example plus accompanying rspec tests
English: a User manages many Listings, and a Listing is managed by many Users. The association is handled by ListingManager via listing_id and manager_id as foreign keys.
In the examples, below notice how one can create willy-nilly method names for the association as long as one defines how to get from one side of the association to the other. Another take away: the info for class_name and foreign_key and source are handled as literal strings for the purposes of the method constructing its SQL behind the scenes; it's only where Rails cannot infer the naming that one has to help out a bit
class ListingManager < ActiveRecord::Base
belongs_to :listing
belongs_to :manager, class_name:"User"
belongs_to :cato, class_name:"User", foreign_key: "manager_id"
end
class Listing < ActiveRecord::Base
has_many :listing_managers
has_many :managers, through: :listing_managers
has_many :pepperonis, through: :listing_managers, source: :cato
end
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name
has_many :listing_managers
has_many :listings, through: :listing_managers
has_many :managed_listings, through: :listing_managers, source: :listing
end
rspec tests:
describe Listing do
it "has a valid factory" do
expect(FactoryGirl.create(:listing)).to be_valid
end
it "has many listing managers" do
m1 = FactoryGirl.build(:user)
m2 = FactoryGirl.build(:user)
l = FactoryGirl.build(:listing)
l.managers << m1
l.managers << m2
expect( l.managers.size ).to eq 2
end
it "should have many listing managers as pepperonis" do
m1 = FactoryGirl.build(:user)
m2 = FactoryGirl.build(:user)
l = FactoryGirl.build(:listing)
l.pepperonis << m1
l.pepperonis << m2
expect( l.pepperonis.size ).to eq 2
end
end
describe User do
before :each do
@user = FactoryGirl.build(:user)
end
it "returns the first name when given a User" do
expect( @user.first_name ).to eq "Cato"
end
it "manages many listings" do
l1 = FactoryGirl.build(:listing)
l2 = FactoryGirl.build(:listing)
@user.listings << l1
@user.listings << l2
expect( @user.listings.size ).to eq 2
end
it "manages many managed_listings" do
l1 = FactoryGirl.build(:listing)
l2 = FactoryGirl.build(:listing)
@user.managed_listings << l1
@user.managed_listings << l2
expect( @user.managed_listings.size ).to eq 2
end
end
describe ListingManager do
it "should have a user as a manager referenced via cato" do
user = FactoryGirl.create(:user, first_name: "Cato")
lm = FactoryGirl.create(:listing_manager)
lm.cato << user
expect(lm.cato.first_name).to eq("Cato")
end
end
Factories:
FactoryGirl.define do
factory :listing_manager do
listing_id 1
manager_id 1
added_at "2013-08-09 10:44:30"
removed_at "2013-08-09 10:44:30"
added_by 1
removed_by 1
end
end
FactoryGirl.define do
factory :listing do
type ""
unit_number "MyString"
space "9.99"
space_units "MyString"
token "MyString"
description "MyString"
title "MyString"
lease_rate "9.99"
lease_rate_units "MyString"
building_id 1
decider_id 1
end
end
FactoryGirl.define do
factory :user do
first_name "Cato"
last_name "delGato"
email {Faker::Internet.email}
username "cato_delgato"
password "1234567890"
password_confirmation "1234567890"
confirmed_at 7.days.ago
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment