Giter Club home page Giter Club logo

rails-activerecord-many-to-many's Introduction

General Assembly Logo

Rails ActiveRecord: many-to-many relationships

Now that we understand one-to-many relationships using ActiveRecord's has_many and belongs_to, we'll look at how to manage many-to-many relationships using the same two macros. The difference is we'll be using the through option for has_many, creating a join table and supporting model if they do not exist, and using belongs_to twice on the join model.

Objectives

  • Diagram a many-to-many relationship using an ERD.
  • Write a migration for a many-to-many relationship.
  • Configure ActiveRecord to manage many-to-many relationships.
  • Create associated records using the rails console.

Instructions

Fork, clone, branch (training), and bundle install.

Next, create your database, migrate, and seed.

Follow along with your instructor, closing your laptop if requested.

Exercise: ERDs

Suppose we have Person, City, and Address. We want to set up two relationships, a one-to-many relationship between Person and Address, and a one-to-many relationship between City and Address.

Diagram these two relationships using an ERD. You should have three entities and two relationships. Using ActiveRecord, we will be able to access City from Person and vice-versa. Draw an additional dotted line to represent this "pseudo"-relationship.

Exercise: Join Table Migration

Generate a model and migration for addresses. addresses should have references to both person and city.

After you generate the migration, inspect it visually and if it looks right, run rake db:migrate. Next enter rails db and inspect the addresses table with \d addresses. Do the columns look as you'd expect? Your output should resemble:

                           Table "public.addresses"
  Column   |  Type   |                       Modifiers
-----------+---------+--------------------------------------------------------
 id         | integer                     | not null default nextval('addresses_id_seq'::regclass)
 category   | character varying           |
 person_id  | integer                     |
 city_id    | integer                     |
 created_at | timestamp without time zone | not null
 updated_at | timestamp without time zone | not null
Indexes:
    "addresses_pkey" PRIMARY KEY, btree (id)
    "index_addresses_on_person_id" btree (person_id)
    "index_addresses_on_city_id" btree (city_id)
Foreign-key constraints:
    "fk_rails_82bb5e9003" FOREIGN KEY (city_id) REFERENCES cities(id)
    "fk_rails_e760e37e14" FOREIGN KEY (person_id) REFERENCES people(id)

If you need to make changes to your migration, run rake db:rollback, edit the migration, and re-run rake db:migrate. If you get stuck, as a last resort you can nuke and pave:

rake db:drop db:create db:migrate db:seed

Rails: has_many :through

Since we are continuing to use has_many, the methods that are generated on our models are the same as before. See ActiveRecord::Associations::ClassMethods documentation for a complete list.

The difference is that this time, we are associating with a join table that should have an associated join model. To be able to access things as we'd expect, we should include both a has_many and has_many through: on the source model.

Code along: Creating Associated Records

We need to set up ActiveRecord to handle our many-to-many relationship from Person to City. Open app/models/person.rb and edit it.

class Person < ActiveRecord::Base
  has_many :cities, through: :addresses
  has_many :addresses
end

Where do we include our inverse_of option? On the join model. We'll be including two belongs_to associations on the join model, so let's hold off on creating app/models/address.rb.

Let's open app/models/city.rb and edit it.

class City < ActiveRecord::Base
  has_many :people, through: :addresses
  has_many :addresses
end

Next, create app/models/address.rb.

class Address < ActiveRecord::Base
  belongs_to :person, inverse_of: :addresses
  belongs_to :city, inverse_of: :addresses
end

Enter rails db. Query the addresses table. It should be empty.

Exit and then enter rails console.

joan = Person.first
boston = City.find_by city: 'Boston', region: 'MA'
dc = City.find_by city: 'Washington', region: 'DC'

joan.cities << dc
joan.cities << boston

joan.cities
joan.addresses

Exit and re-enter rails db. Query the addresses table, the people table, and the cities table. What do you expect to see? Are your expectations met?

Lab: Creating Associated Records

Create a model and migration for companies using the first line of data/companies.csv for the attribute names. Inspect your migration, run rake db:migrate, and check the results in rails db. Add companies to the populate task and load them.

Create a model and migration for jobs. jobs should reference both a person and a company, and have a start_on date, end_on date and a salary stored as an integer. Inspect your migration, run rake db:migrate, and check the results in rails db.

Create a many-to-many relationship between Person and Company through Job. Test your work by associating a person with two companies from the rails console. Inspect the results in rails db.

Best Practice

Never use has_and_belongs_to_many. Always choose has_many through:. It is more expensive to change from the former to latter than to create a simple model and join table from the beginning.

Resources

Source code distributed under the MIT license. Text and other assets copyright General Assembly, Inc., all rights reserved.

rails-activerecord-many-to-many's People

Watchers

Jeremiah Damiron avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.