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,327
 
   
   
  