Model Relationships
In Review
- You now know how to implement all of CRUD!
Web Apps in 4 Steps
- Pick action (new, create, etc.)
- Route to action (usu. use resources)
- Write controller action
- Create view if necessary
Now you know!
What file gets touched second when you type in 'localhost:3000/pokemons'?
-
app/views/pokemons/index.html.erb
-
app/controllers/pokemons_controller.rb
-
config/routes.rb
-
app/models/pokemon.rb
How do I query for all the pokemon that are above level 30?
-
Pokemon.where('level > 30')
-
Pokemon.where(level: '> 30')
-
Pokemon.find(30)
-
@pokemon.level(30)
Assume the Pokemon table has the level column as an integer.
users | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
pokemons | |||
---|---|---|---|
id | name | level | description |
1 | Charmander | 35 | The best starter |
4 | Bulbasaur | 25 | The one no one chooses |
How do I get the Pokemon that belongs to a User with name: "Sam" and id: 2?
-
Pokemon.find(User.find(2))
-
Pokemon.where(id: 2)
-
Pokemon.where(User.name: 'Sam')
-
This is impossible!
users | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
pokemons | |||
---|---|---|---|
id | name | level | description |
1 | Charmander | 5 | The best starter |
4 | Bulbasaur | 2 | The one no one chooses |
Houston, we have a problem!
pokemons | |||
---|---|---|---|
id | name | level | description |
1 | Charmander | 5 | The best starter |
4 | Bulbasaur | 2 | The one no one chooses |
users | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
How does a Pokemon know
which owner it belongs to?
Solution: a new column
pokemons | |||
---|---|---|---|
id | name | level | description |
1 | Charmander | 5 | The best starter |
4 | Bulbasaur | 2 | The one no one chooses |
users | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
pokemons | ||||
---|---|---|---|---|
id | user_id | name | level | description |
1 | 1 | Charmander | 5 | The best starter |
4 | 2 | Bulbasaur | 2 | The one no one chooses |
aka "foreign key"
Key Idea: Model Associations
- One model can belong to another
- One model can have many of another
-
belongs_to in Pokemon
-
has_many in User
In Rails
- Makes sense to ask a user for his/her pokemon:
-
@user.pokemons # [Pokemon(id: 2), ...]
- Also makes sense to ask a pokemon for its user
-
@pokemon.user # User(id: 1)
- Rails does this for us!
Checking the Docs
http://guides.rubyonrails.org/association_basics.html
- You get a bunch of nifty methods just for including :has_many and :belongs_to!
-
@user.pokemons
-
@user.pokemons.build(...)
-
@user.pokemons.size
Which line errors?
@user = User.find(1) @pokemon = Pokemon.find(1) :belongs_to in Pokemon, :has_many in User
-
@pokemon.user
-
@user.pokemons
-
@user.pokemons.size
-
@user.pokemons.build(name: 'Ditto')
users | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
pokemons | |||
---|---|---|---|
id | name | level | description |
1 | Charmander | 5 | The best starter |
4 | Bulbasaur | 2 | The one no one chooses |
What Did I Forget?
- Don't forget to actually make the user_id column!
- How?
Some caveats
- Rails infers column from has_many declaration
- What if you want to change that?
Some caveats
users | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
pokemons | ||||
---|---|---|---|---|
id | trainer_id | name | level | description |
1 | 1 | Charmander | 5 | The best starter |
4 | 2 | Bulbasaur | 2 | The one no one chooses |
has_many :pocket_monsters, class: "Pokemon", foreign_id: "trainer_id"
What about:
users (trainers) | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
gyms | ||
---|---|---|
id | name | num_badges |
1 | pewter city | 0 |
2 | veridian city | 8 |
What we want
- @trainers.gyms
- @gym.trainers
has_many and belongs_to doesn't work!
users (trainers) | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
gyms | ||
---|---|---|
id | name | num_badges |
1 | pewter city | 0 |
2 | veridian city | 8 |
Intermediate table!
users (trainers) | ||
---|---|---|
id | name | num_badges |
1 | Sam | 0 |
2 | Mark | 8 |
gyms | ||
---|---|---|
id | name | num_badges |
1 | pewter city | 0 |
2 | veridian city | 8 |
user_gyms | ||
---|---|---|
id | gym_id | user_id |
1 | 1 | 1 |
2 | 1 | 2 |
Rails: Has and belongs to many
has_many :user_gyms has_many :gyms, through: :user_gyms
has_many :user_gyms has_many :users, through: :user_gyms
belongs_to: user belongs_to: gym
In user.rb
In gym.rb
In user_gyms.rb
Step 0
- Initialize
Step 1
- Migration
Step 2
Step 3
- Model
- Views
Demo!
Spring 2016 - Week 5: Model Relationships
By Rails Decal
Spring 2016 - Week 5: Model Relationships
- 1,214