goals do
div(style: 'margin: 0 auto; width: 250px; height: 120px;') do
model_diagram header: 'Topics', fields: %w(id title description), style: "float: left;"
div(style: 'float: left; position: relative; width: 60px; height: 100px;') do
div(class: 'arrow-left', style: 'left: 0; top: 30px;')
div(class: 'horiz-line', style: 'left: 5px; top: 37px; width: 25px;')
div(class: 'vert-line', style: 'left: 30px; top: 38px; height: 25px;')
div(class: 'horiz-line', style: 'right: 0; top: 62px; width: 30px;')
end
model_diagram header: 'Votes', fields: %w(id topic_id), style: "float: left;"
end
message "Because there is an explicit relationship between a topic and its
votes, we need to specify that. In this step, we'll explicitly
declare the relationship between votes and topics."
end
steps do
step "Teach the Topic model about Votes" do
message "Edit `app/models/topic.rb` so that it looks like this:"
source_code :ruby, <<-RUBY
class Topic < ApplicationRecord
has_many :votes, dependent: :destroy
end
RUBY
end
step "Teach the Vote model about Topics" do
message "Edit `app/models/vote.rb` so that it looks like this:"
source_code :ruby, <<-RUBY
class Vote < ApplicationRecord
belongs_to :topic
end
RUBY
end
step "Play around with Topics and Votes in the Rails console" do
message "First, make sure you've made at least one topic on the site."
console_with_message "Next, open a Rails console in a terminal window:", "rails console"
result <<-CONSOLE
$ rails console
Running via Spring preloader in process 1234
Loading development environment (Rails 5.1.2)
irb(main):001:0>
CONSOLE
tip "To get out of the console, type `exit`."
message "At the console, try the following things"
irb_with_message "See how many topics exist:", "Topic.count"
irb_with_message(
"Save the first topic into a variable:",
"my_topic = Topic.first"
)
tip "`my_topic` here could have been any variable name, but we'll stick with `my_topic` for consistency."
irb_with_message(
"Change the title of that topic to something else:",
"my_topic.update(title: 'Edited in the console')"
)
irb_with_message(
"Add a vote to that topic:",
"my_topic.votes.create"
)
irb_with_message(
"See how many votes that topic has:",
"my_topic.votes.count"
)
irb_with_message(
"Remove a vote from that topic:",
"my_topic.votes.first.destroy"
)
message "Note that the things you can do to **Model classes** (like **Topic** and **Vote**), differ from the things you can do to **Model instances** (like `my_topic`, here). `my_topic.votes` is an **association**, and here behaves mostly like a model class."
div do
half_width "Model class / association methods" do
ul class: 'no-style-type' do
li "Topic.first"
li "Topic.last"
li "Topic.all"
li "Topic.count"
li "Topic.find_by_id(5)"
li "Topic.destroy_all"
li "my_topic.votes.count"
li "my_topic.votes.create"
li "my_topic.votes.destroy_all"
end
end
half_width "Model instance methods" do
ul class: 'no-style-type' do
li "my_topic.title"
li "my_topic.title = 'New title'"
li "my_topic.update(title: 'New title')"
li "my_topic.save"
li "my_topic.save!"
li "my_topic.destroy"
li "my_topic.votes.first.destroy"
end
end
end
message <<-TEXT
An exhaustive list of things you can do to models and associations can be found in the <a href="http://guides.rubyonrails.org/active_record_querying.html">Active Record Query Interface RailsGuide</a>.
TEXT
end
end
explanation do
message <<-MARKDOWN
`has_many` and `belongs_to`:
* In Rails, relationships between models are called associations.
* Associations (usually) come in pairs.
* A topic will have many votes so we put `has_many :votes` in the
topic model.
* When you ask a topic for its votes, you get an array of votes
for that topic.
* A vote is for a particular topic, so we put `belongs_to :topic`
in the vote model.
* When you ask a vote for its topic, you get the topic for that
vote.
It can still be important to clean up after yourself! `dependent: :destroy`
on `has_many :votes` means when a **Topic** gets destroyed, all
the **votes** that correspond to it will be destroyed, too. Without
`dependent: :destroy`, those votes would live on the database forever.
MARKDOWN
end
next_step "allow_people_to_vote"