Other Pages

Expand All

hooking_up_votes_and_topics.step

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 < 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 c"

    result <<-CONSOLE
      $ rails c
      Loading development environment (Rails 5.0.0)
      2.3.0 :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"