From c92fe4538161542c1df35c2b4d2ac8667e17839f Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Sat, 12 Oct 2024 17:08:12 +0100
Subject: [PATCH 01/36] Update intro verbiage
---
javascript/organizing_your_javascript_code/classes.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index 9cd27bb59c9..b44d00a94e3 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -2,9 +2,9 @@
JavaScript does *not* have classes in the same sense as other object-oriented languages like Java or Ruby. ES6, however, *did* introduce a syntax for object creation that uses the `class` keyword. It is basically a new syntax that does the *exact* same thing as the object constructors and prototypes we learned about in the constructor lesson.
-There is a bit of controversy about using the class syntax, however. Opponents argue that `class` is basically just *syntactic sugar* over the existing prototype-based constructors and that it's dangerous and/or misleading to obscure what's *really* going on with these objects. Despite the controversy, classes are beginning to crop up in real code bases that you are almost certainly going to encounter such as frameworks like React (especially if you end up working with class-based React code).
+There has been controversy about using the class syntax, however. Opponents have argued that `class` is basically just *syntactic sugar* over the existing prototype-based constructors and that it's misleading to obscure what's *really* going on with these objects. Because of this, it sometimes trips people up who are already familiar with classes in languages that utilise classical inheritance instead of prototypal inheritance, such as Java or C#. The syntax may look familiar but is still effectively just an alternative syntax for the object constructors and prototypes we've previously covered.
-Since we've already gone fairly in-depth with Constructors, you don't have too much left to learn here beyond the new syntax. If you choose to use classes in your code (that's fine!) you can use them much the same way as object constructors.
+Despite the historical controversy, class syntax now exists in many code bases. There aren't many new mechanisms to learn here, as it's primarily just different syntax for what we've already been able to do with object constructors and prototypes.
### Lesson overview
From 550b54ac0f0b1a3a889d7fe7b33e0bf6d2e58cb0 Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Sat, 12 Oct 2024 17:25:42 +0100
Subject: [PATCH 02/36] Remove pros/cons content
At this point in time, the good/bad controversies aren't so prevalent
given it's now been 9 years since ES6 release.
Many of the resources around criticising or analysing pros/cons of class
syntax appear to be within a year or two of ES6 release, and before
additional features were added, like private properties.
This content has led to several doubts about whether it's worth learning
class syntax and whether it's "bad and shouldn't be used", despite it
now being somewhat commonplace.
---
javascript/organizing_your_javascript_code/classes.md | 5 -----
1 file changed, 5 deletions(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index b44d00a94e3..7267d77e683 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -10,8 +10,6 @@ Despite the historical controversy, class syntax now exists in many code bases.
This section contains a general overview of topics that you will learn in this lesson.
-- Describe the pros and cons of using classes in JavaScript.
-- Briefly discuss how JavaScript's object creation differs from other object-oriented programming languages.
- Explain the differences between an object constructor and a class.
- Explain what "getters" and "setters" are.
- Understand what computed names and class fields are.
@@ -24,7 +22,6 @@ This section contains a general overview of topics that you will learn in this l
-1. Read this article covering [opinions regarding the pros and cons of classes](https://medium.com/@rajaraodv/is-class-in-es6-the-new-bad-part-6c4e6fe1ee65).
1. [JavaScript.info's article on Getters and Setters](https://javascript.info/property-accessors) should get you up to speed on "Getters and Setters", and [JavaScript.info's primer on class syntax](https://javascript.info/class) is probably just about all you need to start using `class` syntax confidently.
1. [MDN's docs on classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are, as usual, a great resource for going a little deeper.
- Take a look at the ['extends' documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends), including the ['Mixins' section](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends#mix-ins). In some frameworks like React, you can use classes to create your components and make them `extend` the core React component which gives you access to all their built-in functionality (though this is not the only way to create components. This will all be covered later in the React section of the course).
@@ -42,8 +39,6 @@ Go back to your [Library project](https://www.theodinproject.com/lessons/node-pa
The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge.
-- [What are some of the pros and cons of using classes in JavaScript?](https://rajaraodv.medium.com/is-class-in-es6-the-new-bad-part-6c4e6fe1ee65)
-- [How does JavaScript's object creation differ from other object-oriented programming languages?](https://rajaraodv.medium.com/is-class-in-es6-the-new-bad-part-6c4e6fe1ee65#e6b3)
- [What differences are there between object constructors and classes?](https://javascript.info/class#not-just-a-syntactic-sugar)
- [What are "getters" & "setters"?](https://javascript.info/property-accessors)
- [What are computed names and class fields?](https://javascript.info/class)
From 9b290882fc06477b21c41e9d01e5175f6bc99640 Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Sat, 12 Oct 2024 17:55:26 +0100
Subject: [PATCH 03/36] Refresh structure and verbiage of assignments
Removed mixins - common pain point as it goes a lot deeper than necessary at this point
---
.../organizing_your_javascript_code/classes.md | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index 7267d77e683..5de46eae0db 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -22,18 +22,19 @@ This section contains a general overview of topics that you will learn in this l
-1. [JavaScript.info's article on Getters and Setters](https://javascript.info/property-accessors) should get you up to speed on "Getters and Setters", and [JavaScript.info's primer on class syntax](https://javascript.info/class) is probably just about all you need to start using `class` syntax confidently.
-1. [MDN's docs on classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are, as usual, a great resource for going a little deeper.
- - Take a look at the ['extends' documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends), including the ['Mixins' section](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends#mix-ins). In some frameworks like React, you can use classes to create your components and make them `extend` the core React component which gives you access to all their built-in functionality (though this is not the only way to create components. This will all be covered later in the React section of the course).
- - Classes can also have [private class properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields) that allow you to implement privacy similarly to factory functions.
- - Classes can have [static properties and methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) which are properties and methods that are accessed on the class itself and not on the instance of a class. This is similar to how some string methods are accessed on the instance of a string itself e.g. `someString.slice(0, 5)` whereas some methods are called on the String constructor directly e.g. `String.fromCharCode(79, 100, 105, 110)`.
+1. Read about [getters and setters](https://javascript.info/property-accessors). While the article doesn't show classes yet, classes can use getters and setters via the same syntax (without `Object.defineProperty`).
+1. Read JavaScript.info's [primer on class syntax](https://javascript.info/class) for an overview of class syntax.
+1. [MDN's docs on classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are, as usual, a great resource for going a little deeper. There are lots of individual syntax features but these can be explored over time. As usual, you're not required to memorize anything just from reading docs here and now. Some good features to have a little look at include:
+ - [Extending classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) (like having a Player class that extends a Person class and inherits from `Person.prototype`).
+ - [Private properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields), allowing you to have properties or methods that are not accessible outside of the class, like with private variables in factory functions.
+ - [Static properties and methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) which are properties and methods (public or private) that are accessed on the class itself and not on the instance of a class. This is similar to how some string methods are accessed on the instance of a string itself e.g. `someString.slice(0, 5)` whereas some methods are called on the String constructor directly e.g. `String.fromCharCode(79, 100, 105, 110)`.
1. [FunFunFunction's video on Composition over Inheritance](https://www.youtube.com/watch?v=wfMtDGfHWpA) gives a great overview of the topic.
-
-
#### Practice
-Go back to your [Library project](https://www.theodinproject.com/lessons/node-path-javascript-library) project and refactor it to use `class` instead of plain constructors. Don't forget to use the git branch workflow you learned in [Revisiting Rock Paper Scissors](https://www.theodinproject.com/lessons/foundations-revisiting-rock-paper-scissors) to work on a new feature. You should get used to working like this!
+Go back to your [Library project](https://www.theodinproject.com/lessons/node-path-javascript-library) and refactor it to use `class` instead of plain constructors. Don't forget to use the git branch workflow you learned in [Revisiting Rock Paper Scissors](https://www.theodinproject.com/lessons/foundations-revisiting-rock-paper-scissors) to work on a new feature. You should get used to working like this!
+
+
### Knowledge check
From 182a62bab571bac35224f24a9b5a51eab4a5dd09 Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Sat, 12 Oct 2024 18:01:24 +0100
Subject: [PATCH 04/36] Move composition/inheritance to OOP Principles lesson
More relevant topics in that lesson as opposed to class syntax.
---
javascript/organizing_your_javascript_code/classes.md | 4 ----
javascript/organizing_your_javascript_code/oop_principles.md | 3 +++
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index 5de46eae0db..6dc84ed5d2c 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -16,7 +16,6 @@ This section contains a general overview of topics that you will learn in this l
- Describe function binding.
- Explain how to implement private class fields and methods.
- Use inheritance with classes.
-- Understand why composition is generally preferred to inheritance.
### Assignment
@@ -28,7 +27,6 @@ This section contains a general overview of topics that you will learn in this l
- [Extending classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) (like having a Player class that extends a Person class and inherits from `Person.prototype`).
- [Private properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields), allowing you to have properties or methods that are not accessible outside of the class, like with private variables in factory functions.
- [Static properties and methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) which are properties and methods (public or private) that are accessed on the class itself and not on the instance of a class. This is similar to how some string methods are accessed on the instance of a string itself e.g. `someString.slice(0, 5)` whereas some methods are called on the String constructor directly e.g. `String.fromCharCode(79, 100, 105, 110)`.
-1. [FunFunFunction's video on Composition over Inheritance](https://www.youtube.com/watch?v=wfMtDGfHWpA) gives a great overview of the topic.
#### Practice
@@ -47,12 +45,10 @@ The following questions are an opportunity to reflect on key topics in this less
- [What are static properties?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static)
- [What are some private class features?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
- [How is inheritance used with classes?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#inheritance)
-- [Why is favoring Composition over Inheritance suggested?](https://www.youtube.com/watch?v=wfMtDGfHWpA)
### Additional resources
This section contains helpful links to related content. It isn't required, so consider it supplemental.
- Stephen Mayeux has a [Youtube playlist on ES6 classes](https://www.youtube.com/playlist?list=PLtwj5TTsiP7uTKfTQbcmb59mWXosLP_7S) and some of their methods with easy to follow examples.
-- Here are some more examples that try to illustrate the [benefits of composition over inheritance](https://blog.beezwax.net/composition-over-inheritance-with-javascript-examples).
- [w3resource](https://www.w3resource.com/javascript-exercises/oop/index.php) provides a comprehensive collection of exercises on classes.
diff --git a/javascript/organizing_your_javascript_code/oop_principles.md b/javascript/organizing_your_javascript_code/oop_principles.md
index 851cd1eb871..f03c1b04463 100644
--- a/javascript/organizing_your_javascript_code/oop_principles.md
+++ b/javascript/organizing_your_javascript_code/oop_principles.md
@@ -15,6 +15,7 @@ This section contains a general overview of topics that you will learn in this l
- Explain the "Single Responsibility Principle".
- Briefly explain the additional SOLID principles.
- Explain what "tightly coupled" objects are and why we want to avoid them.
+- Understand why composition is generally preferred to inheritance.
### Single responsibility
@@ -71,6 +72,7 @@ This one is related pretty strongly to 'Single Responsibility' but takes a diffe
1. Read this article about [SOLID principle #1: Single responsibility (JavaScript)](https://duncan-mcardle.medium.com/solid-principle-1-single-responsibility-javascript-5d9ce2c6f4a5). It simplifies that which is covered in more detail in the SOLID videos below.
1. Watch [The SOLID Design Principles by WDS](https://www.youtube.com/playlist?list=PLZlA0Gpn_vH9kocFX7R7BAe_CvvOCO_p9) to see code examples for each principle.
1. [How to Write Highly Scalable and Maintainable JavaScript: Coupling](https://web.archive.org/web/20200810210808/https://medium.com/@alexcastrounis/how-to-write-highly-scalable-and-maintainable-javascript-coupling-c860787dbdd4) explains loosely coupled objects pretty well.
+1. FunFunFunction has a great video on [favoring composition over inheritance](https://www.youtube.com/watch?v=wfMtDGfHWpA).
@@ -81,6 +83,7 @@ The following questions are an opportunity to reflect on key topics in this less
- [What is the "Single Responsibility Principle"?](#single-responsibility)
- [What are the additional SOLID principles?](https://duncan-mcardle.medium.com/solid-principle-1-single-responsibility-javascript-5d9ce2c6f4a5)
- [What are "tightly coupled" objects and why do we want to avoid them?](https://web.archive.org/web/20200810210808/https://medium.com/@alexcastrounis/how-to-write-highly-scalable-and-maintainable-javascript-coupling-c860787dbdd4)
+- [Why is favoring composition over inheritance suggested?](https://www.youtube.com/watch?v=wfMtDGfHWpA)
### Additional resources
From d50899a8d4564d31f47643889e0411210a2df51c Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Sat, 12 Oct 2024 18:06:16 +0100
Subject: [PATCH 05/36] Reorganise lesson overview and knowledge checks
To match assignment structure
---
.../organizing_your_javascript_code/classes.md | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index 6dc84ed5d2c..d204fd123bf 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -12,10 +12,10 @@ This section contains a general overview of topics that you will learn in this l
- Explain the differences between an object constructor and a class.
- Explain what "getters" and "setters" are.
-- Understand what computed names and class fields are.
-- Describe function binding.
-- Explain how to implement private class fields and methods.
+- Describe basic class syntax.
- Use inheritance with classes.
+- Explain how to implement private class fields and methods.
+- Explain what static properties and methods are.
### Assignment
@@ -40,11 +40,9 @@ The following questions are an opportunity to reflect on key topics in this less
- [What differences are there between object constructors and classes?](https://javascript.info/class#not-just-a-syntactic-sugar)
- [What are "getters" & "setters"?](https://javascript.info/property-accessors)
-- [What are computed names and class fields?](https://javascript.info/class)
-- [What is function binding?](https://javascript.info/class)
-- [What are static properties?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static)
-- [What are some private class features?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
- [How is inheritance used with classes?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#inheritance)
+- [What are some private class features?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
+- [What are static properties?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static)
### Additional resources
From ea68db2eb2e0ca8b5930ceb7031f6a6b870bc43a Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Sat, 12 Oct 2024 18:14:28 +0100
Subject: [PATCH 06/36] Reverse "controversy" content
Less focus on "using classes might not be good" and more focus on how the
underlying mechanics are still the same prototypal inheritance with different
syntax.
---
javascript/organizing_your_javascript_code/classes.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index d204fd123bf..fd759f56eb3 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -2,16 +2,16 @@
JavaScript does *not* have classes in the same sense as other object-oriented languages like Java or Ruby. ES6, however, *did* introduce a syntax for object creation that uses the `class` keyword. It is basically a new syntax that does the *exact* same thing as the object constructors and prototypes we learned about in the constructor lesson.
-There has been controversy about using the class syntax, however. Opponents have argued that `class` is basically just *syntactic sugar* over the existing prototype-based constructors and that it's misleading to obscure what's *really* going on with these objects. Because of this, it sometimes trips people up who are already familiar with classes in languages that utilise classical inheritance instead of prototypal inheritance, such as Java or C#. The syntax may look familiar but is still effectively just an alternative syntax for the object constructors and prototypes we've previously covered.
+Historically, especially when ES6 was released, there was some controversy with class syntax precisely because it looks like classes from languages like Java, but in reality is only syntactic sugar over constructors and prototypes. The underlying mechanisms have not changed despite the different syntax (no classical inheritance going on) but often trips people up since the syntax isn't as explicit about what's *really* going on with these objects.
-Despite the historical controversy, class syntax now exists in many code bases. There aren't many new mechanisms to learn here, as it's primarily just different syntax for what we've already been able to do with object constructors and prototypes.
+Plenty of time has passed though and class syntax now exists in many code bases. There aren't many new mechanisms to learn here, mainly just new syntax for mostly familiar concepts.
### Lesson overview
This section contains a general overview of topics that you will learn in this lesson.
- Explain the differences between an object constructor and a class.
-- Explain what "getters" and "setters" are.
+- Explain what getters and setters are.
- Describe basic class syntax.
- Use inheritance with classes.
- Explain how to implement private class fields and methods.
@@ -39,7 +39,7 @@ Go back to your [Library project](https://www.theodinproject.com/lessons/node-pa
The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge.
- [What differences are there between object constructors and classes?](https://javascript.info/class#not-just-a-syntactic-sugar)
-- [What are "getters" & "setters"?](https://javascript.info/property-accessors)
+- [What are getters and setters?](https://javascript.info/property-accessors)
- [How is inheritance used with classes?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#inheritance)
- [What are some private class features?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
- [What are static properties?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static)
From eb415d8e12c5ed547b3d92e17ae36df9fc7052f0 Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Thu, 7 Nov 2024 20:22:32 +0000
Subject: [PATCH 07/36] Add note about section in assigned article
Section goes out of scope for this TOP lesson.
---
javascript/organizing_your_javascript_code/classes.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index fd759f56eb3..d4ff5e9c3fa 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -21,7 +21,7 @@ This section contains a general overview of topics that you will learn in this l
-1. Read about [getters and setters](https://javascript.info/property-accessors). While the article doesn't show classes yet, classes can use getters and setters via the same syntax (without `Object.defineProperty`).
+1. Read about [getters and setters](https://javascript.info/property-accessors) (don't worry about the "accessor descriptors" section as we have not covered them before). While the article doesn't show classes yet, classes can use getters and setters via the same syntax (without `Object.defineProperty`).
1. Read JavaScript.info's [primer on class syntax](https://javascript.info/class) for an overview of class syntax.
1. [MDN's docs on classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are, as usual, a great resource for going a little deeper. There are lots of individual syntax features but these can be explored over time. As usual, you're not required to memorize anything just from reading docs here and now. Some good features to have a little look at include:
- [Extending classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) (like having a Player class that extends a Person class and inherits from `Person.prototype`).
From cd3c2ffd78808d4e4166ea269a24e5939e5b2bc1 Mon Sep 17 00:00:00 2001
From: Hossam Allam <99792575+Hossam-Allam@users.noreply.github.com>
Date: Thu, 21 Nov 2024 21:08:00 +0300
Subject: [PATCH 08/36] Introduction to grid lesson: fixing flex-box card
exercise link (#29104)
* Fixed link for flexbox card exercise
* Using correct image link
---
intermediate_html_css/grid/introduction_to_grid.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/intermediate_html_css/grid/introduction_to_grid.md b/intermediate_html_css/grid/introduction_to_grid.md
index c7ee97f5ba1..d7ab6a958ed 100644
--- a/intermediate_html_css/grid/introduction_to_grid.md
+++ b/intermediate_html_css/grid/introduction_to_grid.md
@@ -47,7 +47,7 @@ For two-dimensional layouts, you learned a little bit about `flex-wrap`, which a
Remember how much fun you had solving the card layout in this exercise?
-[![flex-exercise-desired-outcome.png](https://i.postimg.cc/vZ81HMkB/flex-exercise-desired-outcome.png)](https://github.com/TheOdinProject/css-exercises/tree/main/flex/07-flex-layout-2)
+[![flex-exercise-desired-outcome.png](https://i.postimg.cc/vZ81HMkB/flex-exercise-desired-outcome.png)](https://github.com/TheOdinProject/css-exercises/tree/main/foundations/flex/07-flex-layout-2)
We know that was a frustrating one, but it's part of the point. While Flexbox allows you to build a layout of rows and columns together, it isn’t always easy.
From 8432c182cb2b02ecf6f2525e3bac29359adacce2 Mon Sep 17 00:00:00 2001
From: dwlknsn
Date: Thu, 21 Nov 2024 12:52:31 -0600
Subject: [PATCH 09/36] ruby-on-rails-advanced-forms: Add link to docs on
checkbox gotcha (#29096)
* ruby-on-rails-advanced-forms: Add link to docs on checkbox gotcha
* Update link text to be more explicit that rails is adding hidden fields
Co-authored-by: Josh Smith
---------
Co-authored-by: Josh Smith
---
ruby_on_rails/advanced_forms_and_activerecord/forms_advanced.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby_on_rails/advanced_forms_and_activerecord/forms_advanced.md b/ruby_on_rails/advanced_forms_and_activerecord/forms_advanced.md
index e2081162beb..9fcf218725b 100644
--- a/ruby_on_rails/advanced_forms_and_activerecord/forms_advanced.md
+++ b/ruby_on_rails/advanced_forms_and_activerecord/forms_advanced.md
@@ -169,7 +169,7 @@ Sometimes, for a record that already exists, you want to either deselect a dropd
Try making a hidden field in your form (or nested form) that has the same name as your checkboxes or dropdown but only contains the value `""`. Now you'll get that attribute to show up in your `params` hash no matter what and you can handle deleting the records however you'd like appropriate.
-Sometimes Rails helper methods will do it for you, but make sure you know what your form is actually submitting (if anything) if you deselect all options!
+Sometimes [Rails helper methods will insert hidden fields for you](https://api.rubyonrails.org/v8.0.0/classes/ActionView/Helpers/FormHelper.html#method-i-checkbox-label-Gotcha), but make sure you know what your form is actually submitting (if anything) if you deselect all options!
### Assignment
From 9f96b802ce232e4974bdc063d3ee507d72d986dc Mon Sep 17 00:00:00 2001
From: dwlknsn
Date: Fri, 22 Nov 2024 23:56:22 +0700
Subject: [PATCH 10/36] Ruby on rails apis_and_building_your_own.md: Remove
dead link (#29110)
Addresses issue https://github.com/TheOdinProject/curriculum/issues/29105
---
ruby_on_rails/apis/apis_and_building_your_own.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/ruby_on_rails/apis/apis_and_building_your_own.md b/ruby_on_rails/apis/apis_and_building_your_own.md
index 5cd99840eff..922896a7834 100644
--- a/ruby_on_rails/apis/apis_and_building_your_own.md
+++ b/ruby_on_rails/apis/apis_and_building_your_own.md
@@ -218,6 +218,5 @@ This section contains helpful links to related content. It isn't required, so co
- Watch this free [Railscast on securing your API](http://railscasts.com/episodes/352-securing-an-api)
- Watch this free [Railscast on versioning your API](http://railscasts.com/episodes/350-rest-api-versioning)
- [GoRails #162 Our First API](https://www.gorails.com/episodes/our-first-api)
-- [Building a public-facing API using view templates instead of `#to_json`](http://blog.codepath.com/2011/05/16/if-youre-using-to_json-youre-doing-it-wrong/)
- [`to_json` or `as_json` by Jonathan Julian](http://jonathanjulian.com/2010/04/rails-to_json-or-as_json/) gives specific examples of digging into the `as_json` method.
- [Service Oriented Architecture Explained](https://www.youtube.com/watch?v=7s_S5Hkm7z0)
From 26dd5c5993980c504ef40e500f15d450ac65cbb0 Mon Sep 17 00:00:00 2001
From: Tobi Oyero
Date: Fri, 22 Nov 2024 16:18:49 -0500
Subject: [PATCH 11/36] Added notes to resume versions
---
getting_hired/applying_and_interviewing/applying.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/getting_hired/applying_and_interviewing/applying.md b/getting_hired/applying_and_interviewing/applying.md
index db290fc7281..d4be25f6178 100644
--- a/getting_hired/applying_and_interviewing/applying.md
+++ b/getting_hired/applying_and_interviewing/applying.md
@@ -30,7 +30,7 @@ The point here is really just to make sure you understand that it's a really ann
### Resume versions
-If you're applying to several different types of positions, tailor your resume for the specific type of opportunity. Just remember that, if you're submitting it virtually, they can see the title.
+If you're applying to several different types of positions, tailor your resume for the specific type of opportunity. Just remember that, if you're submitting it virtually, they can see the title. It's generally a good idea to set the file name of your resume to your name. This has the additional benefit of a recruiter seeing your name and remembering it.
It's also important to note that if you're not gaining traction getting responses with a certain resume, don't be afraid to switch it up. Keep track of the changes and see which version performs better than the others.
From c07bfa182e0ed967342ec89c40c5da32b369ab95 Mon Sep 17 00:00:00 2001
From: dwlknsn
Date: Sun, 24 Nov 2024 18:43:17 -0600
Subject: [PATCH 12/36] Update turbo.md (#29117)
---
ruby_on_rails/rails_sprinkles/turbo.md | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/ruby_on_rails/rails_sprinkles/turbo.md b/ruby_on_rails/rails_sprinkles/turbo.md
index 084bdd52f02..121707ad6f4 100644
--- a/ruby_on_rails/rails_sprinkles/turbo.md
+++ b/ruby_on_rails/rails_sprinkles/turbo.md
@@ -56,17 +56,25 @@ A frame is designated by wrapping a region inside of a `` element.
A basic Turbo Frame, using Rails helpers, may look like so:
```erb
+# with a block
<%= turbo_frame_tag "article" do %>
Some content
<% end %>
+
+# without a block (typically this is used as a placeholder element to be filled later)
+<%= turbo_frame_tag "article" %>
```
which will generate:
```html
+# with a block
Some content
+
+# without a block
+
```
Note that the frames have an ID. The ID is how Turbo is able to identify a frame to find out which one is which.
@@ -130,7 +138,7 @@ We can also do the opposite. We can make a link that exists outside of our Turbo
<%= link_to "Show Posts", posts_path, data: { turbo_frame: "list-region" } %>
<%= link_to "Show Images", images_path, data: { turbo_frame: "list-region" } %>
-<%= turbo_frame_tag id="list-region" %>
+<%= turbo_frame_tag "list-region" %>
```
Clicking either of the above links will send a request to the respective path and return the content inside of our `"list-region"` frame.
@@ -143,7 +151,7 @@ For example:
```erb
...
-<%= turbo_frame_tag id="Articles", src: articles_path do %>
+<%= turbo_frame_tag "Articles", src: articles_path do %>
I am a placeholder! After the request to articles_path is finished,
I will be replaced with the content inside of that page's turbo frame
@@ -156,7 +164,7 @@ We can also make our frames **lazy loaded**. A lazy loaded frame will only fetch
```erb
...
-<%= turbo_frame_tag id="Articles", src: articles_path, loading: "lazy" do %>
+<%= turbo_frame_tag "Articles", src: articles_path, loading: "lazy" do %>
I am a placeholder! I will be replaced when a user scrolls down to see me on the page!
@@ -186,7 +194,7 @@ Our `index` view:
```erb
# views/posts/index.html.erb
-<%= turbo_frame_tag id="new_post", src:new_post_path %>
+<%= turbo_frame_tag "new_post", src: new_post_path %>
<%= render @posts %>
@@ -197,7 +205,7 @@ Our `new` page with it's form:
```erb
# views/posts/new.html.erb
-<%= turbo_frame_tag id="new_post" do %>
+<%= turbo_frame_tag "new_post" do %>
<%= form_with model: @post do |form| %>
<%= form.label :body %>
<%= form.text_area :body %>
From 209f84b2e99621e39f1be602ddca6bc1a1a003f5 Mon Sep 17 00:00:00 2001
From: JeffreyMPrice <108019276+JeffreyMPrice@users.noreply.github.com>
Date: Sun, 24 Nov 2024 19:48:05 -0500
Subject: [PATCH 13/36] Ruby: Project: Caesar Cipher: Fix Ruby Caesar Cipher
code example (#29107)
* Caesar_cipher code example showed right shift, not left.
A left shift of 5 for the string "What a string" should yield the value "Rcvo v nomdib!". The output in the example shows a right shift of 5.
At the very least, the example from Wikipedia shows a left shift of three, "D->A" and "E->B" while the code example shows a right shift. The examples should be consistent on the page.
* Add instructions for right shift
* Add to project instructions using a right shift
* Add to quick tips that Wikipedia shows a left shift
* Fix lower case ceaser
---
ruby/basic_ruby_projects/project_caesar_cipher.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ruby/basic_ruby_projects/project_caesar_cipher.md b/ruby/basic_ruby_projects/project_caesar_cipher.md
index 9f543abcc8f..557ae29a8b8 100644
--- a/ruby/basic_ruby_projects/project_caesar_cipher.md
+++ b/ruby/basic_ruby_projects/project_caesar_cipher.md
@@ -18,7 +18,7 @@ Harvard's CS50 class has a [video about the Caesar cipher](https://www.youtube.c
- Implement a caesar cipher that takes in a string and the shift factor and then outputs the modified string:
+ Implement a Caesar cipher that takes in a string and the shift factor and then outputs the modified string using a right shift:
```ruby
> caesar_cipher("What a string!", 5)
@@ -30,5 +30,6 @@ Harvard's CS50 class has a [video about the Caesar cipher](https://www.youtube.c
- You will need to remember how to convert a string into a number.
- Don't forget to wrap from `z` to `a`.
- Don't forget to keep the same case.
+- The Wikipedia quote discusses a Caesar cipher using a left shift.
From 4e41f5e6390e4568b2a093a475e78a1250cd945e Mon Sep 17 00:00:00 2001
From: Meltasy <119603631+Meltasy@users.noreply.github.com>
Date: Mon, 25 Nov 2024 01:48:43 +0100
Subject: [PATCH 14/36] A Deeper Look at Git:
(#29111)
* Amended Q3 and links in KC to reflect lesson content
* Added periods to lesson overview items
* simplify knowledge check hrefs
* Ruby on rails apis_and_building_your_own.md: Remove dead link (#29110)
Addresses issue https://github.com/TheOdinProject/curriculum/issues/29105
---------
Co-authored-by: dwlknsn
---
git/intermediate_git/a_deeper_look_at_git.md | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/git/intermediate_git/a_deeper_look_at_git.md b/git/intermediate_git/a_deeper_look_at_git.md
index a729fa6e0a0..d8b8bff52b5 100644
--- a/git/intermediate_git/a_deeper_look_at_git.md
+++ b/git/intermediate_git/a_deeper_look_at_git.md
@@ -10,12 +10,12 @@ It is **very important** to take a look at all of this before progressing any fu
This section contains a general overview of topics that you will learn in this lesson.
-- History-changing Git commands
-- Different ways of changing history
-- Using remotes to change history
-- Dangers of history-changing operations
-- Best practices of history-changing operations
-- Pointers
+- History-changing Git commands.
+- Different ways of changing history.
+- Using remotes to change history.
+- Dangers of history-changing operations.
+- Best practices of history-changing operations.
+- Pointers.
### Changing history
@@ -142,7 +142,6 @@ You might be feeling overwhelmed at this point, so let's recap what we've learne
1. Read the chapter on [Rebasing covered by git-scm](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) for an even deeper dive into Rebasing.
-
1. Read the chapter on [Reset covered by git-scm](https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified) for a deeper dive into `git reset`.
@@ -151,9 +150,9 @@ You might be feeling overwhelmed at this point, so let's recap what we've learne
The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge.
-- [Explain what it means for branches to be pointers.](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell)
-- [How can you amend your last commit?](https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things)
-- [What are some different ways to rewrite history?](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
+- [How can you amend your last commit?](#changing-the-last-commit)
+- [What are some different ways to rewrite history?](#changing-multiple-commits)
+- [What does it mean for branches to be pointers?](#branches-are-pointers)
### Additional resources
From 2c5059c8a744500a1e1e10e52715ec68e854eaef Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Mon, 25 Nov 2024 18:44:40 +0000
Subject: [PATCH 15/36] GH Workflows: Include dash delimiter for projects
(#28985)
* Include dash delimiter
* Exclude project- files from lesson linting workflow
---
.github/workflows/markdownlint-lessons.yml | 2 ++
.github/workflows/markdownlint-projects.yml | 2 ++
2 files changed, 4 insertions(+)
diff --git a/.github/workflows/markdownlint-lessons.yml b/.github/workflows/markdownlint-lessons.yml
index 64c5beceb60..0a83ded22df 100644
--- a/.github/workflows/markdownlint-lessons.yml
+++ b/.github/workflows/markdownlint-lessons.yml
@@ -5,6 +5,7 @@ on:
- '**.md'
- '!*'
- '!**/project_*'
+ - '!**/project-*'
- '!archive/**'
- '!templates/**'
- '!markdownlint/docs/**'
@@ -23,6 +24,7 @@ jobs:
**.md
!*
!**/project_*
+ !**/project-*
!archive/**
!templates/**
!markdownlint/docs/**
diff --git a/.github/workflows/markdownlint-projects.yml b/.github/workflows/markdownlint-projects.yml
index bd3c586cac7..081cb183408 100644
--- a/.github/workflows/markdownlint-projects.yml
+++ b/.github/workflows/markdownlint-projects.yml
@@ -3,6 +3,7 @@ on:
pull_request:
paths:
- '**/project_*.md'
+ - '**/project-*.md'
- '!*'
- '!archive/**'
- '!templates/**'
@@ -20,6 +21,7 @@ jobs:
with:
files: |
**/project_*.md
+ **/project-*.md
!*
!archive/**
!templates/**
From 98e5272462a11932d6a9dc54d42eab8bf06a1a1f Mon Sep 17 00:00:00 2001
From: Youssef
Date: Mon, 25 Nov 2024 19:13:09 +0000
Subject: [PATCH 16/36] Project: Sub Strings: Remove unnecessary note (#29125)
* Project: Sub Strings: Remove unnecessary note
As of Ruby 1.9, hashes also maintain order, so the output will be always the same
* Update project_sub_strings.md
---
ruby/basic_ruby_projects/project_sub_strings.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/ruby/basic_ruby_projects/project_sub_strings.md b/ruby/basic_ruby_projects/project_sub_strings.md
index 7816c25f300..28362eb6e15 100644
--- a/ruby/basic_ruby_projects/project_sub_strings.md
+++ b/ruby/basic_ruby_projects/project_sub_strings.md
@@ -28,9 +28,8 @@ Next, make sure your method can handle multiple words:
=> { "down" => 1, "go" => 1, "going" => 1, "how" => 2, "howdy" => 1, "it" => 2, "i" => 3, "own" => 1, "part" => 1, "partner" => 1, "sit" => 1 }
```
-Please note the order of your keys might be different.
-
**Quick Tips:**
- Recall how to turn strings into arrays and arrays into strings.
+
From 1afa0f59c423506a83b11017e0b3c22b3ae8ddd1 Mon Sep 17 00:00:00 2001
From: Balaji Krishnamurthy <107975017+BKM14@users.noreply.github.com>
Date: Tue, 26 Nov 2024 03:00:44 +0530
Subject: [PATCH 17/36] Deployment: Fly.io Hobby plan pricing update (#28978)
* fix broken Jumpstart labs link
* Remove leading whitespace in href
Co-authored-by: Josh Smith
* Fly.io Hobby plan price update
---------
Co-authored-by: Josh Smith
---
ruby_on_rails/rails_basics/deployment.md | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/ruby_on_rails/rails_basics/deployment.md b/ruby_on_rails/rails_basics/deployment.md
index bca88f031fe..331a98d21fa 100644
--- a/ruby_on_rails/rails_basics/deployment.md
+++ b/ruby_on_rails/rails_basics/deployment.md
@@ -93,14 +93,13 @@ Whatever your circumstances, we've got you covered. Here are the PaaS providers
#### Fly.io
- Fly.io uses a CLI tool for deployment.
-- Paid plans include [free allowances](https://fly.io/docs/about/pricing/#free-allowances), additional resources are billed based on usage with very reasonable rates.
+- Paid plans are available, with resource usage billed based on consumption at competitive rates. Free allowances are no longer offered.
- Fly.io charges $0.15/GB of RootFS for machines stopped for 30 days.
##### Fly.io: Hobby Plan
-- New customers get a one-time $5 free trial credit to test Fly.io at no cost. The free allowances are not applicable during the free trial. After the credit has been used, you will be be automatically placed on the $5/month Hobby plan subscription.
-- The longevity of your free trial credit depends on how many resources you consume. More complex apps with more traffic may consume the whole free trial credit within a month, whereas simpler apps may last longer.
-- Requires a credit card.
+- Fly.io no longer offers the $5 free trial credit or the $5/month Hobby plan. However, the free resources previously included in the Hobby (now deprecated), Launch, and Scale plans are still honored for organizations that were on these plans before they were sunset.
+- New users must sign up with a credit card, and charges will apply immediately based on resource consumption.
##### Fly.io: Links
From 51b84f87ab937c0af792c8d789b37a9c4c66ea27 Mon Sep 17 00:00:00 2001
From: Krish Jain <121784348+dekr1sh@users.noreply.github.com>
Date: Tue, 26 Nov 2024 03:07:15 +0530
Subject: [PATCH 18/36] Refactor SQL queries (#29113)
- Updated `GROUP BY` clause to include `users.name` for adherence to
best practices.
- Modified `HAVING` clause to reference `COUNT(posts.id)` directly
instead of the alias `posts_written` aligning with the SQL execution
order, as column aliases are not available during the HAVING phase.
---
databases/databases/databases_and_sql.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/databases/databases/databases_and_sql.md b/databases/databases/databases_and_sql.md
index 7254d39f32f..93731326ecc 100644
--- a/databases/databases/databases_and_sql.md
+++ b/databases/databases/databases_and_sql.md
@@ -101,9 +101,10 @@ Now we're getting into the fun stuff. Aggregate functions like `COUNT` which re
SELECT users.id, users.name, COUNT(posts.id) AS posts_written
FROM users
JOIN posts ON users.id = posts.user_id
- GROUP BY users.id;
+ GROUP BY users.id, users.name;
```
+Note that grouping by `users.name` in addition to `users.id` improves clarity and aligns with best practices by explicitly including all selected non-aggregated columns in the `GROUP BY` clause, though it might not be strictly necessary for most databases.
See [W3Schools' browser-based SQL playground](http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_groupby) for an interactive visual.
The last nifty trick is if you want to only display a subset of your data. In a normal situation, you'd use a `WHERE` clause to narrow it down. But if you've used an aggregate function like `COUNT` (say to get the count of posts written for each user in the example above), `WHERE` won't work anymore. So to conditionally retrieve records based on aggregate functions, you use the `HAVING` function, which is essentially the `WHERE` for aggregates. So say you only want to display users who have written more than 10 posts:
@@ -112,8 +113,8 @@ The last nifty trick is if you want to only display a subset of your data. In a
SELECT users.id, users.name, COUNT(posts.id) AS posts_written
FROM users
JOIN posts ON users.id = posts.user_id
- GROUP BY users.id
- HAVING posts_written >= 10;
+ GROUP BY users.id, users.name
+ HAVING COUNT(posts.id) >= 10;
```
Try going back to [W3Schools' browser-based SQL playground](http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_groupby) and joining the `Customers` and the `Orders` tables to get the number of orders in each country and adding the line `HAVING COUNT(*) > 10;` after `GROUP BY` (and delete the extra semicolon in the previous line).
From 9b72260a2469be1b74a868f605f5159dd61a6ae6 Mon Sep 17 00:00:00 2001
From: Isabella Hansmann <136174454+bellitabellota@users.noreply.github.com>
Date: Tue, 26 Nov 2024 18:23:37 +0000
Subject: [PATCH 19/36] Rephrase a sentence for more clarity (#29130)
---
ruby_on_rails/rails_sprinkles/js_bundling.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby_on_rails/rails_sprinkles/js_bundling.md b/ruby_on_rails/rails_sprinkles/js_bundling.md
index 6445e461cef..7438b431cd0 100644
--- a/ruby_on_rails/rails_sprinkles/js_bundling.md
+++ b/ruby_on_rails/rails_sprinkles/js_bundling.md
@@ -165,7 +165,7 @@ yarn add @hotwired/stimulus
Now when we run `yarn run build` we should get the proper outcome! You should also be able to run `bin/dev` and see the Rails splash page at `http://localhost:3000`.
-Now that we have walked through how to install a Rails app with import maps let's make our life a little bit easier and set it up with jsbundling-rails! Go ahead and enter the below command.
+Now that we have walked through how to install the jsbundling-rails gem in a Rails app that was created with import maps let's make our life a little bit easier and set it up right from the beginning! Go ahead and enter the below command.
```bash
rails new myapp -j with your bundler choice>
From d8aa25154488b4f282fb7845ecfe0d7454336621 Mon Sep 17 00:00:00 2001
From: Mayada <115709272+Maddily@users.noreply.github.com>
Date: Tue, 26 Nov 2024 21:26:00 +0300
Subject: [PATCH 20/36] Improve grammar and punctuation (#29133)
---
react/introduction/setting_up_a_react_environment.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/react/introduction/setting_up_a_react_environment.md b/react/introduction/setting_up_a_react_environment.md
index b3531843de4..93d7b04cc64 100644
--- a/react/introduction/setting_up_a_react_environment.md
+++ b/react/introduction/setting_up_a_react_environment.md
@@ -33,7 +33,7 @@ Yes, but it's *hard*. React is a complex beast and there are many moving parts.
- Compilation ([Babel](https://babeljs.io/))
- React itself
-All of this, and sometimes *much more* is required to get a React project and development environment up and running.
+All of this, and sometimes *much more*, is required to get a React project and development environment up and running.
@@ -97,7 +97,7 @@ This will tell Vite to use the current directory for the project, instead of cre
### Delving deeper
-Let's take a closer look at our new project. Inside you will find some folders, as well as `package.json`, `package-lock.json`, `.gitignore`, and `README.md` files. The `README.md` contains some useful information that you should take the time to skim through now.
+Let's take a closer look at our new project. Inside, you will find some folders, as well as `package.json`, `package-lock.json`, `.gitignore`, and `README.md` files. The `README.md` contains some useful information that you should take the time to skim through now.
The `public` folder is where all of the static assets related to your app will go. This could include images, icons, and information files for the browser.
@@ -122,7 +122,7 @@ Whoa! There's quite a lot here. You are not expected to recognize much of this (
1. We import the `App` component from `App.jsx`, so that we may place (render) it within the DOM.
1. We import some CSS styling (you may recognize this syntax from the Webpack material).
1. We create a `root` object by invoking `createRoot` with an element from our `index.html`.
-1. We invoke the `render` method which is attached to our `root` object, with some very interesting-looking syntax inside the parentheses.
+1. We invoke the `render` method, which is attached to our `root` object, with some very interesting-looking syntax inside the parentheses.
All of this may understandably look unlike anything you've seen up until now, but have no fear, once you've spent the time with this course, you'll know exactly what all of this does, and *much more*.
From 9bcde5edcfbda0b51a64c6167fc26ecd063006fa Mon Sep 17 00:00:00 2001
From: Mayada <115709272+Maddily@users.noreply.github.com>
Date: Tue, 26 Nov 2024 21:32:01 +0300
Subject: [PATCH 21/36] Improve grammar and punctuation (#29131)
---
react/getting_started_with_react/keys_in_react.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/react/getting_started_with_react/keys_in_react.md b/react/getting_started_with_react/keys_in_react.md
index 3da9dc8f5b0..2e2c0e4e2d7 100644
--- a/react/getting_started_with_react/keys_in_react.md
+++ b/react/getting_started_with_react/keys_in_react.md
@@ -11,7 +11,7 @@ This section contains a general overview of topics that you will learn in this l
### Why does React need keys?
-In the upcoming lessons as you learn more about the internal workings of React, more specifically the rerendering process, you will understand the importance of keys. For now, we will keep it short.
+In the upcoming lessons as you learn more about the internal workings of React, more specifically the re-rendering process, you will understand the importance of keys. For now, we will keep it short.
In the previous lesson on rendering lists, we used the `.map()` method to iterate over an array of data and return a list of elements. Now imagine, if any of the items in the list were to change, how would React know which item to update?
@@ -20,9 +20,9 @@ If the list were to change, one of two things *should* happen:
1. we completely re-render the entire list, or:
1. we hunt down the specific items that were changed and only re-render those.
-Assuming we want to hunt down that one specific item that was changed and NOT re-render the entire list. We need something to track that specific item. We can track down a specific item by using a `key`.
+Assuming we want to hunt down that one specific item that was changed and NOT re-render the entire list, we need something to track that specific item. We can track down a specific item by using a `key`.
-When the list is updated for whatever reason, (either from a server or a user interaction), React matches the `keys` of each of the previous list items to the updated list. If there were any changes, React will only update the items that have changed.
+When the list is updated for whatever reason (either from a server or a user interaction), React matches the `keys` of each of the previous list items to the updated list. If there were any changes, React will only update the items that have changed.
As long as `keys` remain consistent and unique, React can handle the DOM effectively and efficiently.
From e44ad37784e8a6d67d37106f37f9f49cc0b903d2 Mon Sep 17 00:00:00 2001
From: DTM_UA <166961473+ProfShibe@users.noreply.github.com>
Date: Wed, 27 Nov 2024 16:00:10 -0600
Subject: [PATCH 22/36] Update variables_and_operators.md
Fix typo. Proper use of the word "edit" would be "editing" in this scenario.
---
foundations/javascript_basics/variables_and_operators.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/foundations/javascript_basics/variables_and_operators.md b/foundations/javascript_basics/variables_and_operators.md
index c352d1a9d05..340da31ece3 100644
--- a/foundations/javascript_basics/variables_and_operators.md
+++ b/foundations/javascript_basics/variables_and_operators.md
@@ -47,7 +47,7 @@ Save and open this file up in a web browser and then open up the browser's conso
1. Click on "Inspect" or "Inspect Element" to open the Developer Tools.
1. Find and select the "Console" tab, where you should see the output of our `console.log` statement.
-**Tip:** You can use [Live Preview extension in Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.live-server) to automatically update the browser when you save your file instead of having to manually refresh the page to see any changes when you edit your code. Try edit the text to say something different!
+**Tip:** You can use [Live Preview extension in Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.live-server) to automatically update the browser when you save your file instead of having to manually refresh the page to see any changes when you edit your code. Try editing the text to say something different!
`console.log()` is the command to print something to the developer console in your browser. You can use this to print the results from any of the following articles and exercises to the console. We encourage you to code along with all of the examples in this and future lessons.
From 59493cbcda0242d3a205397a8b5180a74b18fb9f Mon Sep 17 00:00:00 2001
From: timmy471
Date: Wed, 27 Nov 2024 23:02:09 +0100
Subject: [PATCH 23/36] fix typo in keys_in_react.md
---
react/getting_started_with_react/keys_in_react.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/react/getting_started_with_react/keys_in_react.md b/react/getting_started_with_react/keys_in_react.md
index 2e2c0e4e2d7..38306c4a5fc 100644
--- a/react/getting_started_with_react/keys_in_react.md
+++ b/react/getting_started_with_react/keys_in_react.md
@@ -42,7 +42,7 @@ Keys are passed into the component or a DOM element as a prop. You should alread
```
-Now that we know the syntax, the next question is: what should be used as a key? Ideally, they should be some identifier that is unique to each item in the list. Most databases assign a unique id to each entry, so you shouldn't have to worry about assigning an id yourself. If you are defining data yourself, it is good practice to assign a unique `id` to each item. You can use the [crypto.randomUUID() function](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) to generate a unique id. Let's look at an example:
+Now that we know the syntax, the next question is: what should be used as a key? Ideally, there should be some identifier that is unique to each item in the list. Most databases assign a unique id to each entry, so you shouldn't have to worry about assigning an id yourself. If you are defining data yourself, it is good practice to assign a unique `id` to each item. You can use the [crypto.randomUUID() function](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) to generate a unique id. Let's look at an example:
```jsx
// a list of todos, each todo object has a task and an id
From 5b5c566f8da998a6e2392a88940a823d7db0b194 Mon Sep 17 00:00:00 2001
From: MaoShizhong <122839503+MaoShizhong@users.noreply.github.com>
Date: Thu, 28 Nov 2024 11:02:31 +0000
Subject: [PATCH 24/36] Rephrase "extend" verbiage
Original wording could be misinterpreted to mean that Player.prototype
actually is the same object as Person.prototype, instead of inheriting
from it.
---
javascript/organizing_your_javascript_code/classes.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/javascript/organizing_your_javascript_code/classes.md b/javascript/organizing_your_javascript_code/classes.md
index d4ff5e9c3fa..90fd8934054 100644
--- a/javascript/organizing_your_javascript_code/classes.md
+++ b/javascript/organizing_your_javascript_code/classes.md
@@ -24,7 +24,7 @@ This section contains a general overview of topics that you will learn in this l
1. Read about [getters and setters](https://javascript.info/property-accessors) (don't worry about the "accessor descriptors" section as we have not covered them before). While the article doesn't show classes yet, classes can use getters and setters via the same syntax (without `Object.defineProperty`).
1. Read JavaScript.info's [primer on class syntax](https://javascript.info/class) for an overview of class syntax.
1. [MDN's docs on classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are, as usual, a great resource for going a little deeper. There are lots of individual syntax features but these can be explored over time. As usual, you're not required to memorize anything just from reading docs here and now. Some good features to have a little look at include:
- - [Extending classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) (like having a Player class that extends a Person class and inherits from `Person.prototype`).
+ - [Extending classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) (like having a Player class that extends a Person class, adding `Person.prototype` to the prototype chain).
- [Private properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields), allowing you to have properties or methods that are not accessible outside of the class, like with private variables in factory functions.
- [Static properties and methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) which are properties and methods (public or private) that are accessed on the class itself and not on the instance of a class. This is similar to how some string methods are accessed on the instance of a string itself e.g. `someString.slice(0, 5)` whereas some methods are called on the String constructor directly e.g. `String.fromCharCode(79, 100, 105, 110)`.
From 0f34f36bfaa46c31cb5f8c5dc9509e65030a752a Mon Sep 17 00:00:00 2001
From: Kezy <151378521+Kezy-d4@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:34:02 -0500
Subject: [PATCH 25/36] Fix grammatical error
---
foundations/javascript_basics/object_basics.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/foundations/javascript_basics/object_basics.md b/foundations/javascript_basics/object_basics.md
index 4451c89fb05..be60fae8f2c 100644
--- a/foundations/javascript_basics/object_basics.md
+++ b/foundations/javascript_basics/object_basics.md
@@ -83,7 +83,7 @@ increaseCounterPrimitive(primitive);
Take a moment and guess what will happen to `object` and what will happen to `primitive` after we make the function calls.
-If you answered that the object counter would increase by 1, and the primitive counter wouldn't change, you're correct. Remember that the parameter `objectCounter` contains a *reference* to the same object as the `object` variable we gave it, while `primitiveCounter` contains only a copy of the primitive value only.
+If you answered that the object counter would increase by 1, and the primitive counter wouldn't change, you're correct. Remember that the parameter `objectCounter` contains a *reference* to the same object as the `object` variable we gave it, while `primitiveCounter` only contains a copy of the primitive value.
From e91110b0b1c9f0d46404f48b2419dc82f6e7fe68 Mon Sep 17 00:00:00 2001
From: Mayada <115709272+Maddily@users.noreply.github.com>
Date: Sat, 30 Nov 2024 10:42:35 +0200
Subject: [PATCH 26/36] =?UTF-8?q?Separate=20=E2=80=93s=20for=20plural=20fr?=
=?UTF-8?q?om=20console.log?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It was written as `console.logs`, probably a typo.
---
react/states_and_effects/more_on_state.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/react/states_and_effects/more_on_state.md b/react/states_and_effects/more_on_state.md
index 824fce36097..fa897737a30 100644
--- a/react/states_and_effects/more_on_state.md
+++ b/react/states_and_effects/more_on_state.md
@@ -95,7 +95,7 @@ These are the logs:
![browser console of the above code snippet](https://cdn.statically.io/gh/TheOdinProject/curriculum/103edd69831b1f0e946258009fe36a462c70c163/react/states_and_effects/more_on_state/imgs/00.png)
-Uh-oh, what is happening? Let's break it down (ignore the double `console.logs` for the render case; this is covered in the upcoming lessons).
+Uh-oh, what is happening? Let's break it down (ignore the double `console.log`s for the render case; this is covered in the upcoming lessons).
1. The component renders for the first time. The `person` state variable is initialized to `{ name: 'John', age: 100 }`. The "during render" `console.log` prints the state variable.
1. The button is clicked invoking `handleIncreaseAge`. Interestingly, the `console.log` before and after the `setPerson` call prints the same value.
From 6279714ffb104add0d50546666e17699171c2ee4 Mon Sep 17 00:00:00 2001
From: scuddi <157764402+scuddi@users.noreply.github.com>
Date: Sun, 1 Dec 2024 11:24:16 +0100
Subject: [PATCH 27/36] Change assignment link in
DOM_manipulation_and_events.md
Changed the link/anchor under ### Assignment which links to MDNs Active Learning section on DOM manipulation.
Old link/anchor: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#active_learning_a_dynamic_shopping_list
New link/anchor: #active_learning_basic_dom_manipulation
Old link linked to the second active learning at MDN, new link links to the first active learning which gives the foundation for the second exercise.
I had problems starting with the second exercise, doing the first before helped me a lot and made the second a lot easier.
If this was intended and the link stays the same I would recommend to write at least a hint to the first active learning or state specifically to start with the shopping list.
---
foundations/javascript_basics/DOM_manipulation_and_events.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/foundations/javascript_basics/DOM_manipulation_and_events.md b/foundations/javascript_basics/DOM_manipulation_and_events.md
index 5b6a9bfeb97..8c93c222aba 100644
--- a/foundations/javascript_basics/DOM_manipulation_and_events.md
+++ b/foundations/javascript_basics/DOM_manipulation_and_events.md
@@ -422,7 +422,7 @@ You can find a more complete list with explanations of each event on [W3Schools
Manipulating web pages is the primary benefit of the JavaScript language! These techniques are things that you are likely to be messing with *every day* as a front-end developer, so let's practice!
-1. Complete [MDN's Active Learning sections on DOM manipulation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#active_learning_a_dynamic_shopping_list) to test your skills!
+1. Complete [MDN's Active Learning sections on DOM manipulation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#active_learning_basic_dom_manipulation) to test your skills!
1. Read the following sections from JavaScript Tutorial's series on the DOM to get a broader idea of how events can be used in your pages. Note that some of the methods like `getElementById` are older and see less use today.
As you read, remember that the general ideas can be applied to any event, not only the ones used in examples - but information specific to a certain event type can always be found by checking documentation.
From 3a9ef220a79e27c937bea9521578cca81f8cd65c Mon Sep 17 00:00:00 2001
From: Amal Kariyawasam <12756149+1Amal@users.noreply.github.com>
Date: Tue, 3 Dec 2024 05:09:27 +1100
Subject: [PATCH 28/36] Class Based Components lesson fix for issue #29048
(#29132)
* Class Based Components lesson fix for #29048
Class Based Components: 'Additional resources' points to article which do not
contain information on Class Based Components #29048. Removed additional resources link and replaced with
"It looks like this lesson doesn't have any additional resources yet. Help us expand this section by contributing to our curriculum."
* Added newline character to the bottom of the file
Added newline character to the bottom of the file to fix the lint warning.
---
react/class_components/class_based_components.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/react/class_components/class_based_components.md b/react/class_components/class_based_components.md
index 1d1455278c3..830e27a827f 100644
--- a/react/class_components/class_based_components.md
+++ b/react/class_components/class_based_components.md
@@ -286,4 +286,4 @@ The following questions are an opportunity to reflect on key topics in this less
This section contains helpful links to related content. It isn't required, so consider it supplemental.
-- In general, the React documentation on [thinking in react](https://legacy.reactjs.org/docs/thinking-in-react.html) is a really good place to look into, if you want more practice with class-based components, from scratch.
+- It looks like this lesson doesn't have any additional resources yet. Help us expand this section by contributing to our curriculum.
From fa5e853b2e3efae5d72ef8c9580c41259bac99ed Mon Sep 17 00:00:00 2001
From: Maheshkumar P <67100964+Maheshkumar-novice@users.noreply.github.com>
Date: Mon, 2 Dec 2024 23:40:02 +0530
Subject: [PATCH 29/36] Remove extra new lines from the command snippets
(#29146)
---
git/intermediate_git/working_with_remotes.md | 5 -----
1 file changed, 5 deletions(-)
diff --git a/git/intermediate_git/working_with_remotes.md b/git/intermediate_git/working_with_remotes.md
index a02fa55defa..bc214f2d71a 100644
--- a/git/intermediate_git/working_with_remotes.md
+++ b/git/intermediate_git/working_with_remotes.md
@@ -20,12 +20,10 @@ If you haven't updated your local branch, and you're attempting to `git push` a
You might perform a brief query and find the command `git push --force`. This command overwrites the remote repository with your own local history. So what would happen if we used this while working with others? Well, let's see what would happen when we're working with ourselves. Type the following commands into your terminal, and when the interactive rebase tool pops up remove our commit for `Create fourth file`:
```bash
-
git push origin main
git rebase -i --root
git push --force
git log
-
```
Huh, that's interesting. We can’t find our fourth file on our local system. Let's check our GitHub repository to see if it's there.
@@ -35,18 +33,15 @@ Oh no, we just destroyed it! In this scenario, the danger - you could potential
Let's consider a different scenario:
```bash
-
touch test4.md
git add test4.md && git commit -m "Create fifth file"
git push origin main
git log
-
```
We look at our commit message and realize *oops*, we made a mistake. We want to undo this commit and are once again tempted to just force the push. But wait, remember, this is a **very dangerous command**. If we're ever considering using it, always check if it's appropriate and if we can use a safer command instead. If we're collaborating with others and want to *undo* a commit we just made, we can instead use `git revert`!
```bash
-
git revert HEAD
git push origin main
```
From cf86711419bd1b612a961ffbfd58865e8d193dbd Mon Sep 17 00:00:00 2001
From: Josh Smith
Date: Tue, 3 Dec 2024 14:03:13 -0800
Subject: [PATCH 30/36] Rails Course: Update strong params to use new Rails 8
method (#29127)
* Clarify that `params` is an object (not a hash)
* Convert existing note to notebox
* Update to show new `#expect` method for Strong Parameters
* Fix md lint issues
* Remove old strong parameters explanation
* Update other strong param examples throughout curriculum
---
.../forms_and_authentication/form_basics.md | 6 +-
.../forms_and_authentication/project_forms.md | 2 +-
.../actioncable_lesson.md | 2 +-
ruby_on_rails/rails_basics/controllers.md | 64 ++++++++++++-------
ruby_on_rails/rails_sprinkles/turbo.md | 2 +-
5 files changed, 48 insertions(+), 28 deletions(-)
diff --git a/ruby_on_rails/forms_and_authentication/form_basics.md b/ruby_on_rails/forms_and_authentication/form_basics.md
index 73056cb30de..acd512f1bbc 100644
--- a/ruby_on_rails/forms_and_authentication/form_basics.md
+++ b/ruby_on_rails/forms_and_authentication/form_basics.md
@@ -82,7 +82,7 @@ Each one of these inputs is structured slightly differently, but there are some
Will result in your `params` hash containing a key called `description` that you can access as normal, e.g. `params[:description]`, inside your controller. That's also why some inputs like radio buttons (where `type="radio"`) use the `name` attribute to know which radio buttons should be grouped together such that clicking one of them will unclick the others. The `name` attribute is surprisingly important!
-Now another thing we talked about in the controller section was nesting data. You'll often want to tuck submitted data neatly into a hash instead of keeping them all at the top level. This can be useful because, as we saw with controllers, it lets you do a one-line `#create` (once you've allowed the parameters with `#require` and `#permit`). When you access `params[:user]`, it's actually a hash containing all the user's attributes, for instance `{first_name: "foo", last_name: "bar", email: "foo@bar.com"}`. How do you get your forms to submit parameters like this? It's easy!
+Now another thing we talked about in the controller section was nesting data. You'll often want to tuck submitted data neatly into a hash instead of keeping them all at the top level. This can be useful because, as we saw with controllers, it lets you do a one-line `#create` (once you've allowed the parameters with `#expect`). When you access `params[:user]`, it's actually a hash containing all the user's attributes, for instance `{first_name: "foo", last_name: "bar", email: "foo@bar.com"}`. How do you get your forms to submit parameters like this? It's easy!
It all comes back to the `name` attribute of your form inputs. Just use hard brackets to nest data like so:
@@ -102,7 +102,7 @@ Those inputs will now get transformed into a nested hash under the `:user` key.
Specific parameters of the `params` hash are accessed like any other nested hash `params[:user][:email]`.
-Don't forget that you have to allow the params now in your controller using `require` and `permit` because they are a hash instead of just a flat string. See the Controller section below for a refresher on the controller side of things.
+Don't forget that you have to allow the params now in your controller using `#expect` because they are a hash instead of just a flat string. See the Controller section below for a refresher on the controller side of things.
This is cool stuff that you'll get a chance to play with in the project.
@@ -244,7 +244,7 @@ Just as a refresher, here's a very basic controller setup for handling `#new` ac
end
def user_params
- params.require(:user).permit(:first_name, :last_name, :other_stuff)
+ params.expect(user: [:first_name, :last_name, :other_stuff])
end
...
```
diff --git a/ruby_on_rails/forms_and_authentication/project_forms.md b/ruby_on_rails/forms_and_authentication/project_forms.md
index 3559a13dd49..4a7d17aedec 100644
--- a/ruby_on_rails/forms_and_authentication/project_forms.md
+++ b/ruby_on_rails/forms_and_authentication/project_forms.md
@@ -71,7 +71,7 @@ That looks a whole lot like what you normally see when Rails does it, right?
1. You'll get some errors because now your controller will need to change. But recall that we're no longer allowed to just directly call `params[:user]` because that would return a hash and Rails' security features prevent us from doing that without first validating it.
1. Go into your controller and comment out the line in your `#create` action where you instantiated a `::new` User (we'll use it later).
-1. Implement a private method at the bottom called `user_params` which will `permit` and `require` the proper fields (see the [Controllers Lesson](/lessons/ruby-on-rails-controllers) for a refresher).
+1. Implement a private method at the bottom called `user_params` which will `expect` the proper fields (see the [Controllers Lesson](/lessons/ruby-on-rails-controllers) for a refresher).
1. Add a new `::new` User line which makes use of that new allow params method.
1. Submit your form now. It should work marvelously (once you debug your typos)!
diff --git a/ruby_on_rails/mailers_advanced_topics/actioncable_lesson.md b/ruby_on_rails/mailers_advanced_topics/actioncable_lesson.md
index c72652b0fc9..fc09e8b2e3e 100644
--- a/ruby_on_rails/mailers_advanced_topics/actioncable_lesson.md
+++ b/ruby_on_rails/mailers_advanced_topics/actioncable_lesson.md
@@ -459,7 +459,7 @@ end
private
def message_params
- params.require(:message).permit(:body)
+ params.expect(message: [:body])
end
```
diff --git a/ruby_on_rails/rails_basics/controllers.md b/ruby_on_rails/rails_basics/controllers.md
index 8b48af13715..ce642d78be0 100644
--- a/ruby_on_rails/rails_basics/controllers.md
+++ b/ruby_on_rails/rails_basics/controllers.md
@@ -8,7 +8,7 @@ It's pretty straightforward. Typical controllers are pretty lightweight and don'
The controller's `#index` action would actually look like:
-~~~ruby
+```ruby
PostsController < ApplicationController
...
def index
@@ -16,7 +16,7 @@ The controller's `#index` action would actually look like:
end
...
end
-~~~
+```
In this action, we have the controller asking the model for something ("Hey, give me all the posts!"), packaging them up in an instance variable `@posts` so the view can use them, then will automatically render the view at `app/views/posts/index.html.erb` (we'll talk about that in a minute).
@@ -34,21 +34,21 @@ This section contains a general overview of topics that you will learn in this l
One way that Rails makes your life a bit easier is that it assumes things are named a certain way and then executes them behind the scenes based on those names. For instance, your controller and its action have to be named whatever you called them in your `routes.rb` file when you mapped a specific type of HTTP request to them.
-The other end of the process is what the controller does when it's done. Once Rails gets to the `end` of that controller action, it grabs all the instance variables from the controller and sends them over the view file _which is named the same thing as the controller action_ and which lives in a folder named after the controller, e.g. `app/views/posts/index.html.erb`. This isn't arbitrary, this is intentional to make your life a lot easier when looking for files later. If you save your files in a different folder or hierarchy, you'll have to explicitly specify which ones you want rendered.
+The other end of the process is what the controller does when it's done. Once Rails gets to the `end` of that controller action, it grabs all the instance variables from the controller and sends them over the view file *which is named the same thing as the controller action* and which lives in a folder named after the controller, e.g. `app/views/posts/index.html.erb`. This isn't arbitrary, this is intentional to make your life a lot easier when looking for files later. If you save your files in a different folder or hierarchy, you'll have to explicitly specify which ones you want rendered.
### Rendering and redirecting
Although Rails will implicitly render a view file that is named the same thing as your controller action, there are plenty of situations when you might want to override it. A main case for this is when you actually want to completely redirect the user to a new page instead of rendering the result of your controller action.
-Redirects typically occur after controller actions where you've submitted information like to create a new Post. There's no reason to have a `create.html.erb` view file that gets displayed once a post has been created... we usually just want to see the post we created and so we'll redirect over to the Show page for that post. The distinction here is that your application treats a redirect as _a completely new HTTP request_... so it would enter through the router again, look for the Show page corresponding to that post, and render it normally. That also means that any instance variables you set in your original `#create` controller action are wiped out along the way.
+Redirects typically occur after controller actions where you've submitted information like to create a new Post. There's no reason to have a `create.html.erb` view file that gets displayed once a post has been created... we usually just want to see the post we created and so we'll redirect over to the Show page for that post. The distinction here is that your application treats a redirect as *a completely new HTTP request*... so it would enter through the router again, look for the Show page corresponding to that post, and render it normally. That also means that any instance variables you set in your original `#create` controller action are wiped out along the way.
If that's the common way to deal with successfully creating an object, how about when it fails for some reason (like the user entered a too-short post title)? In that case, you can just render the view for another controller action, often the same action that created the form you just submitted (so the `#new` action).
-The trick here is that the view page gets passed the instance variables from your _current_ controller action. So let's say that you tried to `#create` a Post and stored it to `@post` but it failed to save. You then rendered the `#new` action's view and that view will receive the `@post` you were just working with in the `#create` action. This is great because you don't have to wipe the form completely clean (which is really annoying as a user) -- you can just identify the fields that failed and have the user resubmit. It may sound a bit abstract now but you'll see the difference quickly when building.
+The trick here is that the view page gets passed the instance variables from your *current* controller action. So let's say that you tried to `#create` a Post and stored it to `@post` but it failed to save. You then rendered the `#new` action's view and that view will receive the `@post` you were just working with in the `#create` action. This is great because you don't have to wipe the form completely clean (which is really annoying as a user) -- you can just identify the fields that failed and have the user resubmit. It may sound a bit abstract now but you'll see the difference quickly when building.
Let's see it in code:
-~~~ruby
+```ruby
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
...
@@ -74,7 +74,7 @@ Let's see it in code:
end
end
end
-~~~
+```
So the thing to pay attention to is that, if we successfully are able to save our new post in the database, we redirect to that post's show page. Note that a shortcut you'll see plenty of times is, instead of writing `redirect_to post_path(@post.id)`, just write `redirect_to @post` because Rails knows people did that so often that they gave you the option of writing it shorthand. We'll use this in the example as we develop it further.
@@ -86,7 +86,7 @@ It's important to note that `render` and `redirect_to` do NOT immediately stop y
If you write something like:
-~~~ruby
+```ruby
def show
@user = User.find(params[:id])
if @user.is_male?
@@ -94,7 +94,7 @@ If you write something like:
end
render "show-girl"
end
-~~~
+```
In any case where the user is male, you'll get hit with a multiple render error because you've told Rails to render both "show-boy" and "show-girl".
@@ -102,7 +102,7 @@ In any case where the user is male, you'll get hit with a multiple render error
In the example above, we saw `... code here to set up a new @post based on form info ...`. Okay, how do we grab that info? We keep saying that the router packages up all the parameters that were sent with the original HTTP request, but how do we access them?
-With the `params` hash! It acts just like a normal Ruby hash and contains the parameters of the request, stored as `:key => value` pairs. So how do we get the ID of the post we're asking for? `params[:id]`. You can access any parameters this way which have "scalar values", e.g. strings, numbers, booleans, `nil`... anything that's "flat".
+With the `params` object! The `params` object is an instance of `ActionController::Parameters`, and it behaves similarly to a normal Ruby hash. It contains the parameters of the request stored as `:key => value` pairs. So how do we get the ID of the post we're asking for? `params[:id]`. You can access any parameters this way which have "scalar values", e.g. strings, numbers, booleans, `nil`... anything that's "flat".
Some forms will submit every field as a top level scalar entry in the params hash, e.g. `params[:post_title]` might be "My Test Post Title" and `params[:post_body]` might be "Body of post!" etc and these you can access with no issues. You have control over this, as you'll learn in the lessons on forms.
@@ -114,15 +114,19 @@ In our example, we will assume that our `params[:post]` is giving us a hash of P
The important distinction between the "scalar" parameter values like strings and more complex parameters like hashes and arrays is that Rails 4 implemented some protections in the controller, called "Strong Parameters". This is so the user can't send you harmful data (like automatically setting themselves as an admin user when they create an account). To do this, Rails makes you explicitly verify that you are willing to accept certain items of a hash or array.
-_Note: This used to be done in Rails 3 by setting `attr_accessible` in the model to allow attributes, so you will probably see that in a lot of Stack Overflow posts and earlier applications._
+
-To explicitly allow parameters, you use the methods `require` and `permit`. Basically, you `require` the name of your array or hash to be in Params (otherwise it'll throw an error), and then you `permit` the individual attributes inside that hash to be used. For example:
+ This used to be done in Rails 3 by setting `attr_accessible` in the model to allow attributes, so you will probably see that in a lot of Stack Overflow posts and earlier applications.
-~~~ruby
+
+
+To explicitly allow parameters, you can call the `#expect` method on the `params`. Usually this method will be passed a key matching the name of the model you're working with (ie. a `post`) followed by an array of allowed attributes. For example:
+
+```ruby
def allowed_post_params
- params.require(:post).permit(:title,:body,:author_id)
+ params.expect(post: [:title, :body, :author_id])
end
-~~~
+```
This will return the hash of only those params that you explicitly allow (e.g. `{:title => "your title", :body => "your body", :author_id => "1"}` ). If you didn't do this, when you tried to access params[:post] nothing would show up! Also, if there were any additional fields submitted inside the hash, these will be stripped away and made inaccessible (to protect you).
@@ -130,7 +134,7 @@ It can be inconvenient, but it's Rails protecting you from bad users. You'll usu
So our `#create` action above can now be filled out a bit more:
-~~~ruby
+```ruby
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
...
@@ -153,10 +157,24 @@ So our `#create` action above can now be filled out a bit more:
# gives us back just the hash containing the params we need to
# to create or update a post
def allowed_post_params
- params.require(:post).permit(:title,:body,:author_id)
+ params.expect(post: [:title, :body, :author_id])
end
end
-~~~
+```
+
+
+
+ Prior to Rails 8, strong parameters were handled differently. Instead of the `#expect` method, you had to call `#permit` on the top level key name followed by calling `#require` on the list of attributes. For example:
+
+ ```ruby
+ def allowed_post_params
+ params.permit(:post).require(:title, :body, :author_id)
+ end
+ ```
+
+ This way still works, but it has a couple of security flaws that motivated the development of `#expect`. But you will likely be exposed to this way of doing it through older projects, blog posts, and StackOverflow answers. Just know that this is serving the same function as the new `#expect` method.
+
+
### Flash
@@ -174,7 +192,7 @@ The distinction between `flash` and `flash.now` just lets Rails know when it wil
Now the full controller code can be written out for our `#create` action:
-~~~ruby
+```ruby
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
...
@@ -195,10 +213,10 @@ Now the full controller code can be written out for our `#create` action:
private
def allowed_post_params
- params.require(:post).permit(:title,:body,:author_id)
+ params.expect(post: [:title, :body, :author_id])
end
end
-~~~
+```
So that action did a fair bit of stuff -- grab the form data, make a new post, try to save the post, set up a success message and redirect you to the post if it works, and handle the case where it doesn't work by berating you for your foolishness and re-rendering the form. A lot of work for only 10 lines of Ruby. Now that's smart controlling.
@@ -207,12 +225,14 @@ So that action did a fair bit of stuff -- grab the form data, make a new post, t
That's really just a taste of the Rails controller, but you should have a pretty good idea of what's going on and what tricks you can use.
+
1. Read the [Rails Guides chapter on Controllers](http://guides.rubyonrails.org/action_controller_overview.html), sections 1 - 4.6.3 and 5.2. We'll cover sessions (section 5.1) more in the future so don't worry about them now.
+
### Knowledge check
-This section contains questions for you to check your understanding of this lesson. If you’re having trouble answering the questions below on your own, review the material above to find the answer.
+The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge.
- [What does a controller do?](https://guides.rubyonrails.org/action_controller_overview.html#what-does-a-controller-do-questionmark)
- [Why is it important to adhere to the Rails naming convention for your controllers and all of its methods?](#naming-matters)
diff --git a/ruby_on_rails/rails_sprinkles/turbo.md b/ruby_on_rails/rails_sprinkles/turbo.md
index 121707ad6f4..d936a7c85a8 100644
--- a/ruby_on_rails/rails_sprinkles/turbo.md
+++ b/ruby_on_rails/rails_sprinkles/turbo.md
@@ -250,7 +250,7 @@ class PostsController < ApplicationController
private
def post_params
- params.require(:post).permit(:body)
+ params.expect(post: [:body])
end
end
```
From 0a3c81c464c14b169327832d52d0274419dcc1bd Mon Sep 17 00:00:00 2001
From: Fred Love
Date: Wed, 4 Dec 2024 15:25:32 -0500
Subject: [PATCH 31/36] Update join_the_odin_community.md
---
foundations/introduction/join_the_odin_community.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/foundations/introduction/join_the_odin_community.md b/foundations/introduction/join_the_odin_community.md
index 1166af648ae..ee42d3047fc 100644
--- a/foundations/introduction/join_the_odin_community.md
+++ b/foundations/introduction/join_the_odin_community.md
@@ -184,7 +184,7 @@ Sometimes there are misunderstandings and interactions go poorly. You are a volu
- **If you wouldn't say it out loud don't type it:** Plain and simple.
- **Ping (@user) with a purpose:** Only @ another user when it is necessary. Include your question or comment in the message. Wait until they reply before pinging again.
- **Don't 'bomb' chats:** Don't send multiple messages in a row; type out your whole message, then push send.
- - **Don't exclude anyone:** These are public chats; if someone joins in on a conversation, include them!
+ - **Don't exclude anyone:** These are public chats; if someone joins in on a conversation, include them! The exception to this is when someone is helping a learner. Those need to be 1:1 conversations to not confuse the learner.
- **Don't disappear right after asking for help on code:** If you're posting a question, make sure you have time to stick around and discuss it with those trying to help!
From 8dfd17c40a6865ecbbdc90e5591c34bbe78cc14d Mon Sep 17 00:00:00 2001
From: Fred Love
Date: Wed, 4 Dec 2024 17:41:38 -0500
Subject: [PATCH 32/36] Update join_the_odin_community.md (#29151)
---
foundations/introduction/join_the_odin_community.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/foundations/introduction/join_the_odin_community.md b/foundations/introduction/join_the_odin_community.md
index 1166af648ae..92ee62b43f9 100644
--- a/foundations/introduction/join_the_odin_community.md
+++ b/foundations/introduction/join_the_odin_community.md
@@ -186,6 +186,7 @@ Sometimes there are misunderstandings and interactions go poorly. You are a volu
- **Don't 'bomb' chats:** Don't send multiple messages in a row; type out your whole message, then push send.
- **Don't exclude anyone:** These are public chats; if someone joins in on a conversation, include them!
- **Don't disappear right after asking for help on code:** If you're posting a question, make sure you have time to stick around and discuss it with those trying to help!
+ - **Take some time to observe the server before jumping in:** This helps you understand how our community interacts and communicates.
From b140cf499a2e4a67c0985cb7e957f30ab10fb523 Mon Sep 17 00:00:00 2001
From: Isabella Hansmann <136174454+bellitabellota@users.noreply.github.com>
Date: Wed, 4 Dec 2024 22:44:01 +0000
Subject: [PATCH 33/36] Rails - Advanced Forms and Active Record: Update
wording and section numbers indicated in the assignment (#29149)
* Rephrase a sentence for more clarity
* Update wording and chapter numbers of assignment section
---
.../active_record_queries.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ruby_on_rails/advanced_forms_and_activerecord/active_record_queries.md b/ruby_on_rails/advanced_forms_and_activerecord/active_record_queries.md
index a54afea1834..9c178ea9f08 100644
--- a/ruby_on_rails/advanced_forms_and_activerecord/active_record_queries.md
+++ b/ruby_on_rails/advanced_forms_and_activerecord/active_record_queries.md
@@ -224,15 +224,15 @@ This was a lot of material, but you should have a healthy appreciation for the b
1. Read the first 6 sections of the [Rails Guide on Active Record Querying](http://guides.rubyonrails.org/active_record_querying.html) for a more basic overview of query functions. Don't worry too much about batching and `#find_each`.
1. Read section 20 of the same Rails guide for a brief look at [using `exists?`, `any?` and `many?`](https://guides.rubyonrails.org/active_record_querying.html#existence-of-objects).
-1. Read sections 7, 8 and 21 of the same Rails guide for an understanding of [aggregate functions and the calculations you can run on them](https://guides.rubyonrails.org/active_record_querying.html#grouping).
-1. Skim sections 9-12 of the same Rails guide on [overriding conditions](https://guides.rubyonrails.org/active_record_querying.html#overriding-conditions).
+1. Read sections 7 and 21 to learn about [grouping and aggregate functions](https://guides.rubyonrails.org/active_record_querying.html#grouping).
+1. Skim section 8 to learn about [overriding conditions](https://guides.rubyonrails.org/active_record_querying.html#overriding-conditions).
1. Read section 12 of the same Rails guide to see how Rails lets you play with [joining tables together](https://guides.rubyonrails.org/active_record_querying.html#joining-tables).
1. Read section 18 of the same Rails guide for a quick look at [the helpful `find_or_create_by` methods](https://guides.rubyonrails.org/active_record_querying.html#find-or-build-a-new-object).
#### Advanced querying
1. Read section 14 in the [Rails Guide on Querying](https://guides.rubyonrails.org/active_record_querying.html#scopes) for a look at scopes. Again, you don't necessarily need to memorize all the details of scopes, but you should understand the concept and when it might be useful.
-1. Read section 19 of the same Rails guide for a look at [using SQL directly to query](http://guides.rubyonrails.org/active_record_querying.html#finding-by-sql).
+1. Read section 19 “Finding by SQL” of the same Rails guide for a look at [using SQL directly to query](http://guides.rubyonrails.org/active_record_querying.html#finding-by-sql).
From 08d8b5c59a5b4d20805e92e600214a3f3c44fd04 Mon Sep 17 00:00:00 2001
From: Rushil