Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialUlises Reyes
9,152 PointsNeed help understanding RSpec "let!" method
So I'm in the "Editing Todo Lists" lesson and understood how everything works until the let! method is introduced
does
let!(:todo_list) {TodoList.create(title: 'Groceries', description: 'Grocery List.')}
create a 'todo_list' variable that contains a new todo list entry? I tested it out by removing the line
todo_list = options[:todo_list]
from my 'update_todo_list' method and no longer referencing 'todo_list:' as an option when calling it, and it worked. So does that mean that let! creates a global variable?
However, if I change the name of the variable in the 'let!' method to something like:
let!(:water) {TodoList.create(title: 'Groceries', description: 'Grocery List.')}
and inside of the update_todo_list method I include
todo_list = options[:todo_list]
and call the method as such
update_todo_list todo_list: water, title: "New Title", description: "New description."
I get an error:
Failure/Error: within "#todo_list_#{todo_list.id}" do
NoMethodError:
undefined method `id' for nil:NilClass
Which makes no sense to me since Im filling the value of the variable 'todo_list' with the 'water' variable
replacing the above line with
within "#todo_list_#{water.id}" do
then i no longer have an error, but a new error appear saying that todo_list is undefined on the line that contains
todo_list.reload
again, replacing it with
water.reload
will work, but I dont know why including
todo_list = options[:todo_list]
as part of the update function and calling it with
update_todo_list todo_list: water, title: "New Title", description: "New description."
does work. This isn't a particular roadblock to my learning, but its annoying to not understand how things work fully. If anyone here has any understanding of rspec, i would like for you to chime in
1 Answer
Jason Seifer
Treehouse Guest TeacherHey Ulises Reyes! Great question. There are two different versions of rspec's let
method: let
and let!
. The difference is subtle but important. With let
the variable is lazily created, which means that Ruby won't create or access the contents of it until it needs to, which is generally when it is called in a test. The let!
method with an exclamation point creates the variables immediately. Generally that is done to give you earlier access to the variables or use them earlier in the test.
When you call the method update_todo_list
, a new variable is created inside of that method. We are passing in the individual todo list via the options[:todo_list]
variable to use inside of that method only. That would let us call the method many times with different todo list variables. When a variable is used in a method without an @
sign, it becomes a local variable to that method.
The distinction is a little bit more strange when we get in to rspec and the way that the let
method is handled. The let
method will create that todo_list
or water
variable but it exists more as a method rather than a specific variable. When ruby looks for a variable called todo_list
it is actually calling a method which returns our todo list. That method is specified in the block after let(:todo_list) **{ ... }**
.
We could have written the update_todo_list
method to just use the todo_list
variable/method we create with let
. However, if we ever wanted to send in a different todo list to that method, we'd have to modify the method body. By using an argument to the method, we can save ourselves some coding later on down the line. This would come in handy if we ever extracted that method out to a helper file.