Other Pages

Hooking Up Votes And Topics

Goals

    Topics
    id
    title
    description
    Votes
    id
    topic_id

    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 1: Teach the Topic model about Votes

Edit app/models/topic.rb so that it looks like this:

class Topic < ApplicationRecord
  has_many :votes, dependent: :destroy
end

Step 2: Teach the Vote model about Topics

Look into app/models/vote.rb and confirm that it looks like this:

class Vote < ApplicationRecord
  belongs_to :topic
end

Step 3: Play around with Topics and Votes in the Rails console

First, make sure you've made at least one topic on the site.

Next, open a Rails console in the shell window:
rails console
Approximate expected result:
~/RandomWittyName$ rails console
Loading development environment (Rails 7.0.1)
irb(main):001:0>
The greyed-out text may differ and is not important.

Are you typing into the shell or are you typing into the rails console? This makes a big difference. You can always tell the two apart by the prompt

At the console, try the following things

See how many topics exist:
Topic.count
Approximate expected result:
irb(main):001:0> Topic.count
  Topic Count (0.2ms)  SELECT COUNT(*) FROM "topics"
=> 2
The greyed-out text may differ and is not important.
  • On the first line you see
    • the irb-prompt ending in with a greater-than sign, and after that
    • the code you typed in
  • on the second line, you can see (from right to left)
    • the SQL Query that was sent to the database SELECT COUNT(*) FROM "topics"
    • that it took 0.2ms to run that Query
    • that it was run to compute the Topic count
  • on the third line you see
    • a "fat arrow" =>
    • and after that the result: there is are two topics in this database

Most of the time you are only intrested in the last line with the result.

Save the first topic into a variable:
my_topic = Topic.first

my_topic here could have been any variable name, but we'll stick with my_topic for consistency.

Change the title of that topic to something else:
my_topic.update(title: 'Edited in the console')

Reload the page in the browser and you will see the change:

screenshot of the web app in the browser showing new title

Add a vote to that topic:
my_topic.votes.create
See how many votes that topic has:
my_topic.votes.count
Remove a vote from that topic:
my_topic.votes.first.destroy

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.

Model class / association methods
  • Topic.first
  • Topic.last
  • Topic.all
  • Topic.count
  • Topic.find_by_id(5)
  • Topic.destroy_all
  • my_topic.votes.count
  • my_topic.votes.create
  • my_topic.votes.destroy_all
Model instance methods
  • my_topic.title
  • my_topic.title = 'New title'
  • my_topic.update_attributes(title: 'New title')
  • my_topic.save
  • my_topic.save!
  • my_topic.destroy
  • my_topic.votes.first.destroy

An exhaustive list of things you can do to models and associations can be found in the Active Record Query Interface RailsGuide.

Explanation

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.

Next Step: