Skip to content

Commit

Permalink
Merge pull request #47 from jmkoni/average-ratings-schools
Browse files Browse the repository at this point in the history
add averages to schools
  • Loading branch information
jmkoni authored Jun 20, 2019
2 parents 7ceb4c8 + 34ca6e7 commit dd72631
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 9 deletions.
2 changes: 1 addition & 1 deletion app/controllers/courses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class CoursesController < ApplicationController
# GET /courses
# GET /courses.json
def index
courses = Course.all.with_averages
courses = Course.with_averages
if params[:school_id].to_i.zero?
(@filterrific = initialize_filterrific(
courses,
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/schools_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ class SchoolsController < ApplicationController
# GET /schools.json
def index
(@filterrific = initialize_filterrific(
School.all,
School.with_averages,
params[:filterrific],
select_options: {
sorted_by: School.options_for_sorted_by
}
)) || return
@schools = @filterrific.find.page(params[:page])
@schools = @filterrific.find
end

# GET /schools/1
Expand Down
1 change: 1 addition & 0 deletions app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class Course < ApplicationRecord
.left_joins(:reviews, :school)
.group('courses.id, schools.id')
}

def full_number
"#{department} #{number}"
end
Expand Down
35 changes: 34 additions & 1 deletion app/models/school.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ class School < ApplicationRecord
available_filters: %i[
sorted_by
search_query
with_avg_rating_gte
with_avg_difficulty_lte
with_avg_work_lte
]
)

Expand Down Expand Up @@ -47,11 +50,38 @@ class School < ApplicationRecord
order(Arel.sql("LOWER(schools.short_name) #{direction}"))
when /^name_/
order(Arel.sql("LOWER(schools.name) #{direction}"))
when /^avg_rating_/
order(Arel.sql("avg_rating #{direction}"))
when /^avg_difficulty_/
order(Arel.sql("avg_difficulty #{direction}"))
when /^avg_work_/
order(Arel.sql("avg_work #{direction}"))
else
raise(ArgumentError, "Invalid sort option: #{sort_option.inspect}")
end
}

scope :with_avg_rating_gte, ->(ref_num) {
having('avg(reviews.rating) >= ?', ref_num)
}

scope :with_avg_difficulty_lte, ->(ref_num) {
having('avg(reviews.difficulty) <= ?', ref_num)
}

scope :with_avg_work_lte, ->(ref_num) {
having('avg(reviews.work_required) <= ?', ref_num)
}

scope :with_averages, -> {
select('schools.*,
avg(reviews.rating) as avg_rating,
avg(reviews.difficulty) as avg_difficulty,
avg(reviews.work_required) as avg_work')
.left_joins(courses: [:reviews])
.group('schools.id')
}

def self.options_for_select
schools = School.arel_table
order(schools[:name].lower).pluck(:name, :id)
Expand All @@ -62,7 +92,10 @@ def self.options_for_sorted_by
['Name (a-z)', 'name_asc'],
['Name (z-a)', 'name_desc'],
['Short Name (a-z)', 'short_name_asc'],
['Short Name (z-a)', 'short_name_desc']
['Short Name (z-a)', 'short_name_desc'],
['Average Rating (highest first)', 'avg_rating_desc'],
['Average Work Required (lowest first)', 'avg_work_asc'],
['Average Difficulty (lowest first)', 'avg_difficulty_asc']
]
end
end
Expand Down
9 changes: 7 additions & 2 deletions app/views/schools/_list.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<% if schools.load.empty? %>
No schools at this time!
<% else %>
<%= page_entries_info schools, class: 'align-middle' %>
Displaying <strong><%= pluralize(schools.size, 'school') %></strong>
<% end %>
</div>
<div class="col-md-2">
Expand All @@ -19,6 +19,9 @@
<tr>
<th scope="col"><%= filterrific_sorting_link(@filterrific, :name) %></th>
<th scope="col"><%= filterrific_sorting_link(@filterrific, :short_name) %></th>
<th scope="col"><%= filterrific_sorting_link(@filterrific, :avg_rating) %></th>
<th scope="col"><%= filterrific_sorting_link(@filterrific, :avg_difficulty) %></th>
<th scope="col"><%= filterrific_sorting_link(@filterrific, :avg_work) %></th>
<th scope="col" colspan="2"></th>
</tr>
</thead>
Expand All @@ -28,6 +31,9 @@
<tr>
<td><%= link_to school.name, school %></td>
<td><%= school.short_name %></td>
<td><%= school.avg_rating.round(1) %></td>
<td><%= school.avg_difficulty.round(1) %></td>
<td><%= school.avg_work.round(1) %></td>
<% if can? :manage, School %>
<td><%= link_to 'Edit', edit_school_path(school) %></td>
<td><%= link_to 'Delete', school, method: :delete, data: { confirm: 'Are you sure?' } %></td>
Expand All @@ -36,5 +42,4 @@
<% end %>
</tbody>
</table>
<%= paginate schools %>
</div>
20 changes: 20 additions & 0 deletions app/views/schools/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="form-group">
<label class="font-weight-bold">Average rated higher than</label>
<%= f.number_field(:with_avg_rating_gte) %>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label class="font-weight-bold">Average difficulty lower than</label>
<%= f.number_field(:with_avg_difficulty_lte) %>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label class="font-weight-bold">Average work required lower than</label>
<%= f.number_field(:with_avg_work_lte) %>
</div>
</div>
</div>
<% end %>
</div>

Expand Down
2 changes: 1 addition & 1 deletion app/views/users/_list.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<% if users.load.empty? %>
No users at this time!
<% else %>
<%= page_entries_info users, class: 'align-middle' %>
<%= page_entries_info users %>
<% end %>
</div>
<div class="col-md-2">
Expand Down
2 changes: 1 addition & 1 deletion spec/controllers/schools_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

it 'assigns schools to @schools' do
get :index
expect(assigns(:schools).size).to eq(3)
expect(assigns(:schools).length).to eq(3)
end

it 'renders the index template' do
Expand Down
77 changes: 76 additions & 1 deletion spec/models/school_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,98 @@
school1 = create(:school, name: 'Alphabets', short_name: 'abc')
school2 = create(:school, name: 'Zebra', short_name: 'xyz')
school3 = create(:school, name: 'Cows', short_name: 'Bovine')
course1 = create(:course, school: school1)
course2 = create(:course, school: school2)
course3 = create(:course, school: school3)
review1 = create(:review, course: course1, work_required: 1, difficulty: 5, rating: 10)
review2 = create(:review, course: course2, work_required: 5, difficulty: 10, rating: 1)
review3 = create(:review, course: course3, work_required: 10, difficulty: 1, rating: 5)
aggregate_failures do
expect(School.sorted_by('name_asc').first).to eq school1
expect(School.sorted_by('name_desc').first).to eq school2
expect(School.sorted_by('short_name_asc').first).to eq school1
expect(School.sorted_by('short_name_desc').first).to eq school2
expect(School.with_averages.sorted_by('avg_work_desc').first).to eq school3
expect(School.with_averages.sorted_by('avg_work_asc').first).to eq school1
expect(School.with_averages.sorted_by('avg_rating_desc').first).to eq school1
expect(School.with_averages.sorted_by('avg_rating_asc').first).to eq school2
expect(School.with_averages.sorted_by('avg_difficulty_desc').first).to eq school2
expect(School.with_averages.sorted_by('avg_difficulty_asc').first).to eq school3
expect { School.sorted_by('oh_no') }.to raise_error(ArgumentError, 'Invalid sort option: "oh_no"')
end
end
end

describe 'with_avg_rating_gte' do
it 'gets all reviews with query in review' do
school1 = create(:school)
school2 = create(:school)
school3 = create(:school)
course1 = create(:course, school: school1)
course2 = create(:course, school: school2)
course3 = create(:course, school: school3)
review1 = create(:review, rating: 10, course: course1)
review2 = create(:review, rating: 2, course: course2)
review3 = create(:review, rating: 5, course: course3)
aggregate_failures do
expect(School.with_averages.with_avg_rating_gte(3).length).to eq 2
expect(School.with_averages.with_avg_rating_gte(3)).not_to include school2
expect(School.with_averages.with_avg_rating_gte(3)).to include school1
expect(School.with_averages.with_avg_rating_gte(3)).to include school3
end
end
end

describe 'with_avg_difficulty_lte' do
it 'gets all reviews with query in review' do
school1 = create(:school)
school2 = create(:school)
school3 = create(:school)
course1 = create(:course, school: school1)
course2 = create(:course, school: school2)
course3 = create(:course, school: school3)
review1 = create(:review, difficulty: 4, course: course1)
review2 = create(:review, difficulty: 10, course: course2)
review3 = create(:review, difficulty: 2, course: course3)
aggregate_failures do
expect(School.with_averages.with_avg_difficulty_lte(5).length).to eq 2
expect(School.with_averages.with_avg_difficulty_lte(5)).not_to include school2
expect(School.with_averages.with_avg_difficulty_lte(5)).to include school1
expect(School.with_averages.with_avg_difficulty_lte(5)).to include school3
end
end
end

describe 'with_avg_work_lte' do
it 'gets all reviews with query in review' do
school1 = create(:school)
school2 = create(:school)
school3 = create(:school)
course1 = create(:course, school: school1)
course2 = create(:course, school: school2)
course3 = create(:course, school: school3)
review1 = create(:review, work_required: 10, course: course1)
review2 = create(:review, work_required: 5, course: course2)
review3 = create(:review, work_required: 15, course: course3)
aggregate_failures do
expect(School.with_averages.with_avg_work_lte(10).length).to eq 2
expect(School.with_averages.with_avg_work_lte(10)).to include school1
expect(School.with_averages.with_avg_work_lte(10)).to include school2
expect(School.with_averages.with_avg_work_lte(10)).not_to include school3
end
end
end
end
context 'methods' do
it 'returns options for sorted by' do
expected_options = [
['Name (a-z)', 'name_asc'],
['Name (z-a)', 'name_desc'],
['Short Name (a-z)', 'short_name_asc'],
['Short Name (z-a)', 'short_name_desc']
['Short Name (z-a)', 'short_name_desc'],
['Average Rating (highest first)', 'avg_rating_desc'],
['Average Work Required (lowest first)', 'avg_work_asc'],
['Average Difficulty (lowest first)', 'avg_difficulty_asc']
]
expect(School.options_for_sorted_by).to eq expected_options
end
Expand Down

0 comments on commit dd72631

Please sign in to comment.