goals {
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."
}
steps {
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 < ActiveRecord::Base
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 < ActiveRecord::Base
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 c"
result <<-CONSOLE
$ rails c
Loading development environment (Rails 4.0.0)
1.9.3-p194 :001 >
CONSOLE
message "At the console, try the following things"
console_with_message "See how many topics exist:", "Topic.count"
console_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."
console_with_message "Change the title of that topic to something else:", "my_topic.update_attributes(title: 'Edited in the console')"
console_with_message "Add a vote to that topic:", "my_topic.votes.create"
console_with_message "See how many votes that topic has:", "my_topic.votes.count"
console_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_attributes(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
}
explanation {
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
}
next_step "allow_people_to_vote"