-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into revert-158-revert-139-93-databases--orms
- Loading branch information
Showing
9 changed files
with
638 additions
and
4 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
--- | ||
title: Class vs Instance Methods | ||
length: 90 | ||
layout: page | ||
--- | ||
|
||
## Learning Goals | ||
|
||
- Identify use cases for class methods and instance methods in the context of a Rails app | ||
- Identify available AR methods depending on current context of `self` | ||
- Differentiate when to use a class method or an instance method | ||
|
||
## Set Up | ||
|
||
This lesson plan starts with the `class-vs-instance-setup` branch of our good old Set List Tutorial Repo. Get it [here](https://github.com/turingschool-examples/set-list-7/tree/class-vs-instance-setup). Then, follow the normal setup tasks: | ||
|
||
- Run `bundle install` | ||
- Run `rails db:{drop,create,migrate,seed}` | ||
|
||
## Exploration | ||
|
||
Open up `artist.rb` and `artist_spec.rb` side-by-side in your code editor. You'll notice a `pry` in some of the methods defined in the Artist class. You can run the spec with `bundle exec rspec spec/models/artist_spec.rb` to hit the first pry. You can enter `exit` into pry to continue on to the next pry. Use the code, test, and each of the `prys` to answer the following questions with your group in a break out room: | ||
|
||
For each of the methods defined in the Artist class: | ||
|
||
- Is the method defined as a class or instance method? | ||
- What is the value of `self` inside the method? | ||
- How do you call the method? In other words, what can you call the method on? | ||
- How can you update the method body to use `self`? | ||
|
||
**Discussion Questions** | ||
|
||
- What is a class method? | ||
- What is an instance method? | ||
- What is self in each context? | ||
- What does an instance of a model represent in our DB? | ||
- What does the class of a model represent in our DB? | ||
|
||
## Takeaways | ||
<section class="answer"> | ||
<h3>Review these after your discussion</h3> | ||
* In a Rails app, a class method allows you to perform actions on or query data from an entire database table rather than one specific row (or instance) of the data. `self` refers to the entire class or table. | ||
* In an instance method, you can perform actions or retrieve information about one instance of the class, which represents one row of data in a database table. `self` in these methods refers to the single model object. | ||
</section> | ||
|
||
## Practice Problems | ||
|
||
Using model tests and the corresponding models only, write methods that will: | ||
|
||
- Return all songs sorted by title alphabetically | ||
- Return all of an artist's songs sorted by title alphabetically | ||
- Return the `x` shortest songs, where `x` is an argument for the method | ||
- Return the `x` shortest songs for an artist, where `x` is an argument for the method | ||
|
||
**Spicy** | ||
|
||
- Return a song's artist's name | ||
- Return the number of songs for an artist that have at least 1 play and a length greater than 0 | ||
- Return a list of songs that have a title that contains the word "love" | ||
- Return the 3 songs that have the most plays, a length greater than `x` where `x` can be any integer value, and were updated within the last three days | ||
|
||
Answers to these practice problems can be found on the `class-vs-instance-solutions` branch [here](https://github.com/turingschool-examples/set-list-7/tree/class-vs-instance-solutions). | ||
|
||
## Checks for Understanding | ||
Answer the following questions either in your notebook or by taking [this review quiz](https://forms.gle/BG6JfUSAhSioYero6). | ||
|
||
- How do you know whether a task requires a class or an instance method? | ||
- What are some common error messages we might see if we confuse a class method with an instance method and vice versa? | ||
- How can we list the methods available for self in pry? | ||
- What does an instance of a model represent in our DB? | ||
- What does the class of a model represent in our DB? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
--- | ||
title: Intro to Class Methods (in Rails) | ||
length: 45 | ||
layout: page | ||
--- | ||
|
||
## Learning Goals | ||
|
||
- Review Class Methods in Ruby | ||
- Explore examples of Class Methods using Active Record | ||
|
||
### Warm Up | ||
|
||
1. Using your own words, write down a definition of 'class methods' in Ruby. How do they work? | ||
2. The code example below defines a Ruby class with one instance method and one class method. Come up with one more instance method and one more class method on your own, and describe how each of the methods would be used. | ||
|
||
```ruby | ||
class Inventory | ||
|
||
def initialize(name) | ||
@name = name | ||
@equipment = [] | ||
end | ||
|
||
def store(equipment) | ||
@equipment << equipment | ||
"This inventory now contains #{equipment}." | ||
end | ||
|
||
def self.store | ||
"A person's inventory can store up to 10 pieces of equipment." | ||
end | ||
end | ||
``` | ||
|
||
## Set Up | ||
|
||
This lesson uses the [Intro to Ruby on Rails repo](https://github.com/turingschool-examples/intro_to_ror_demo/tree/main) from your intermission work. Clone it now if you haven't already, and check out a new `class_methods` branch. | ||
|
||
We'll need more data to work with for this lesson. Open the `db/seeds.rb` file and add the following lines: | ||
|
||
```ruby | ||
Subject.create!(title: 'Trigonometry', description: 'Angles and calculating them', difficulty: 4) | ||
Subject.create!(title: 'Music History', description: 'Beyond the Beatles', difficulty: 1) | ||
Subject.create!(title: 'Orientation', description: 'Learning about remote learning', difficulty: 1) | ||
Subject.create!(title: 'Revisions 201', description: 'Drafting was the easy part', difficulty: 4) | ||
``` | ||
|
||
Then run the following commands: | ||
|
||
```bash | ||
bundle | ||
rails db:{drop,create,migrate,seed} | ||
``` | ||
|
||
## Exploration | ||
|
||
Let's say we need to be able to return the easiest subjects from our database. "Easy" subjects have a difficulty of 3 or less, and this list should be ordered from easiest to most difficult. | ||
|
||
This query is straightforward in Active Record. Open your rails console and try this query: | ||
|
||
```ruby | ||
Subject.where("difficulty <= ?", 3).order(:difficulty) | ||
``` | ||
|
||
This should return 4 objects that meet the criteria described above. Great! How do you think this works? | ||
|
||
### Using class methods in Rails models | ||
|
||
We know that in Ruby, class methods are called on the class name itself (rather than on an instance). For example: | ||
|
||
```ruby | ||
my_inventory = Inventory.new("Marcille Donato") | ||
my_inventory.store("Ambrosia") # instance method called on an instance of the Inventory class | ||
Inventory.store # class method called on the Inventory class | ||
``` | ||
|
||
You might have noticed that we called the Active Record query above on the `Subject` model-- that is, on the class name itself and not an instance. In order to look at all instances of `Subject` in the database and compare them to the criteria we provided, AR **has** to use class methods. | ||
|
||
Add this method to the Subject class: | ||
|
||
```ruby | ||
def self.easy_subjects | ||
binding.pry | ||
end | ||
``` | ||
|
||
Now, go into `rails c` again and call `Subject.easy_subjects`. What does `self` return in your pry? (You may have to run `Subject.connection` first). Keep in mind that calling `self` inside of a method is very different from prepending `self.` to a method definition. | ||
|
||
### What is going on with 'self' in instance and class methods? | ||
|
||
The scope within Ruby methods work in such a way that `self` is __implied__. This means that anything we call within this method is called on whatever the `self` object is in that moment! | ||
|
||
Therefore, in this pry session, if we wanted to return all rows from the `subjects` table, we don't even need to use the class name `Subject`; it's already implied. Try running these in your pry session: | ||
|
||
* `all` | ||
* `first` | ||
* `where(title: "Literature")` | ||
|
||
To illustrate how `self` can behave differently, let's add an instance method and pry into it: | ||
|
||
```ruby | ||
def format_summary | ||
binding.pry | ||
end | ||
``` | ||
|
||
```ruby | ||
# in rails console: | ||
subject = Subject.first | ||
subject.format_summary | ||
``` | ||
|
||
In this pry session, `self` returns an `Subject` object, a single instance. Again, `self` is implied, and we don't need to write that in our method in order to call other methods on the object. Try running the following commands in your pry session: | ||
|
||
* `id` | ||
* `title` | ||
* `created_at` | ||
|
||
This means that we can call on a model instance's attributes directly from within an instance method. | ||
|
||
```ruby | ||
def format_summary | ||
"#{title} - #{description}" | ||
end | ||
``` | ||
|
||
### Putting it all together | ||
|
||
Class methods are extremely valuable in Rails applications. One very common way to utilize them is to make SQL and AR queries reusable and DRY, encapsulating this data logic in a Model rather than writing the query every time it's needed in something like a Controller. | ||
|
||
Back to our challenge: return the easiest subjects from our database ordered by ascending difficulty. Put the query we used earlier into a class method, so that it can be called on `Subject`. | ||
|
||
```ruby | ||
class Subject < ApplicationRecord | ||
|
||
def self.easy_subjects | ||
where("difficulty <= ?", 3).order(:difficulty) | ||
end | ||
end | ||
``` | ||
|
||
Then try it out in `rails c`: | ||
|
||
```ruby | ||
Subject.easy_subjects | ||
``` | ||
|
||
## Checks for Understanding | ||
|
||
Answer the following questions in your notebook or gist: | ||
|
||
- What is the difference between using `self` as part of a method definition, and using `self` from within a method scope? | ||
- What does the class of a model represent in our DB? | ||
- What does an instance of a model represent in our DB? |
Oops, something went wrong.