Other Pages

Expand All

hooking_up_votes_and_topics.step

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"