Reputation: 53
Let's say in my controller, I use a "where" clause on Teachers
so I can put the alias, class_size
, on the number of students
@teachers = Teachers.select("teachers.*, count(students.id) as class_size")
When I create a view page for indexing all the teachers and use @teacher.class_size
, it returns the count of students like a charm...
<% for teacher in @teachers %>
<% = teacher.name %>
<% = teacher.class_size %>
...
<% end %>
So, I write up my index
spec like so...
RSpec.describe "teachers/index" do
let(:teacher) { create(:teacher) }
let(:student) { create(:student) }
before do
assign(:teachers, [teacher])
render
end
...
But, when I run the spec, I get an error that says
# --- Caused by: ---
# NoMethodError:
# undefined method `class_size' for an instance of Teacher
How do I go about writing my test spec for the index
page and not run into errors with the class_size
alias? I want to maintain the alias I set up with the select
method call
Upvotes: 0
Views: 75
Reputation: 2483
The "magic" that added the class_size
reader attribute to your @teaches instance has been done by AREL under the hood when you have written this:
@teachers = Teachers.select("teachers.*, count(students.id) as class_size")
In the spec you have mocked that variable, thus you won't have that reader accessor method, unless you mock it or, even better, you assign it to the same query result object:
before do
assign(:teachers, Teachers.select("teachers.*, count(students.id) as class_size"))
render
end
Upvotes: 0
Reputation: 102016
In order to select the additional column you need to actually fetch the records from the database instead of just passing an array of records instanciated in your factory to your view spec.
class Teacher < ApplicationRecord
# ...
scope :with_student_count, ->{
left_joins(:students)
.select("teachers.*, count(students.id) as class_size")
}
end
RSpec.describe "teachers/index" do
let(:teacher) { create(:teacher) }
let(:student) { create(:student) } # this isn't even associated with the teacher?
before do
assign(:teachers, Teacher.with_student_count)
render
end
...
You could also use a counter-cache to avoid the need to fetch the count or mock the method for the purpose of the test.
Or you could just forgo the view spec altogether and test your view and the controller together though a feature/system spec.
Upvotes: 1