Commit 7421d9c8

mo khan <mo@mokhan.ca>
2014-10-18 18:30:36
add a category search filter.
1 parent 81b8d33
app/controllers/concerns/pageable.rb
@@ -0,0 +1,12 @@
+module Pageable
+  extend ActiveSupport::Concern
+  DEFAULT_PER_PAGE=12
+
+  def page
+    params[:page]
+  end
+
+  def per_page
+    params[:per_page] || DEFAULT_PER_PAGE
+  end
+end
app/controllers/application_controller.rb
@@ -1,4 +1,5 @@
 class ApplicationController < ActionController::Base
+  include Pageable
   # Prevent CSRF attacks by raising an exception.
   # For APIs, you may want to use :null_session instead.
   protect_from_forgery with: :exception
app/controllers/creations_controller.rb
@@ -1,6 +1,6 @@
 class CreationsController < ApplicationController
   def index
-    @creations = FindAllCreationsQuery.new.fetch(params)
+    @creations = AllCakesQuery.new.fetch(params).page(page).per(per_page)
   end
 
   def show
app/models/concerns/filterable.rb
@@ -0,0 +1,11 @@
+module Filterable
+  extend ActiveSupport::Concern
+
+  module ClassMethods
+    def filtered_by(search_filters)
+      search_filters.inject(self) do |memo, next_filter|
+        next_filter.call(memo)
+      end
+    end
+  end
+end
app/models/creation/repository.rb
@@ -1,5 +1,7 @@
 class Creation
+  include Filterable
   scope :tagged, ->(tag) { tagged_with([tag]).where('photos_count > 0') }
+  scope :published, ->() { unscoped.distinct.includes(:user, :photos).joins(:photos).where('photos.image_processing' => nil) }
 
   class Repository < SimpleDelegator
     def initialize(connection = Creation)
@@ -15,10 +17,6 @@ class Creation
       connection.includes(:user, :photos).where(["upper(name) like :query OR upper(story) like :query", { query: "%#{query.upcase}%" }])
     end
 
-    def visible_creations
-      connection.unscoped.distinct.includes(:user, :photos).joins(:photos).where('photos.image_processing' => nil)
-    end
-
     private
 
     attr_reader :connection
app/services/application/all_cakes_query.rb
@@ -0,0 +1,23 @@
+class AllCakesQuery
+  def initialize(repository = Spank::IOC.resolve(:cakes))
+    @repository = repository
+  end
+
+  def fetch(params)
+    @repository.filtered_by(search_filters_for(params))
+  end
+
+  private
+
+  def search_filters_for(params)
+    [
+      ->(cakes) { cakes.published },
+      ->(cakes) { params[:category].blank? ? cakes.all : cakes.where(category_id: Category.find_by_slug(params[:category].downcase).id) },
+      ->(cakes) { cakes.order(created_at: sort(params)) },
+    ]
+  end
+
+  def sort(params)
+    params[:sort] == "oldest" ? :asc : :desc
+  end
+end
app/services/application/find_all_creations_query.rb
@@ -1,22 +0,0 @@
-class FindAllCreationsQuery
-  DEFAULT_PER_PAGE=12
-
-  def initialize(repository = Spank::IOC.resolve(:cakes))
-    @repository = repository
-  end
-
-  def fetch(params)
-    @repository.visible_creations.order(created_at: sort(params)).page(params[:page]).per(per_page(params))
-  end
-
-  private
-
-  def per_page(params)
-    params[:per_page] || DEFAULT_PER_PAGE
-  end
-
-  def sort(params)
-    params[:sort] == "oldest" ? :asc : :desc
-  end
-end
-
spec/features/creations_spec.rb
@@ -1,13 +1,13 @@
 require 'rails_helper'
 
-describe "Creations" do
+describe "Creations", js: true do
   describe "GET /creations" do
     before :each do
       visit creations_path
     end
 
-    it "should load the page properly" do
-      page.should have_content("CakeSide")
+    it "loads the page" do
+      expect(page).to have_content("CakeSide")
     end
   end
 end
spec/models/creation/repository_spec.rb
@@ -20,7 +20,7 @@ describe Creation::Repository do
     end
   end
 
-  describe "#visible_creations" do
+  describe "#published" do
     let!(:user){ create(:user) }
     let!(:published_cake){ create(:creation, user: user) }
 
@@ -28,7 +28,7 @@ describe Creation::Repository do
       published_cake.photos.create(image: 'example.png', image_processing: nil)
     end
 
-    let(:results) { subject.visible_creations }
+    let(:results) { subject.published }
 
     it "returns cakes that do not have photos that are processing" do
       expect(results.count).to eql(1)
spec/models/creation_repository_spec.rb
@@ -1,30 +0,0 @@
-require "rails_helper"
-
-describe CreationRepository do
-  describe "#visible_creations" do
-    let!(:user){ create(:user) }
-    let!(:published_cake){ create(:creation, user: user) }
-
-    before :each do
-      published_cake.photos.create(image: 'example.png', image_processing: nil)
-    end
-
-    let(:results) { subject.visible_creations }
-
-    it "returns cakes that do not have photos that are processing" do
-      expect(results.count).to eql(1)
-      expect(results).to include(published_cake)
-    end
-  end
-
-  describe "#search" do
-    let(:cake) { create(:creation, name: 'Cake') }
-    let(:cup_cake) { create(:creation, name: 'Cup Cake') }
-
-    it "returns cakes with a matching name" do
-      results = subject.search('cake')
-      expect(results).to include(cake)
-      expect(results).to_not include(cup_cake)
-    end
-  end
-end
spec/services/application/all_cakes_query_spec.rb
@@ -0,0 +1,41 @@
+require "rails_helper"
+
+describe AllCakesQuery do
+  subject { AllCakesQuery.new }
+
+  context "with no filters" do
+    let!(:cake_with_a_photo) { create(:cake) }
+    let!(:cake_without_a_photo) { create(:cake, photos: []) }
+
+    before :each do
+      cake_with_a_photo.photos << create(:photo)
+    end
+
+    it "returns all cakes with at least one photo" do
+      results = subject.fetch({})
+      expect(results).to include(cake_with_a_photo)
+    end
+
+    it "ignores cakes without a photo" do
+      results = subject.fetch({})
+      expect(results).to_not include(cake_without_a_photo)
+    end
+  end
+
+  context "with filters" do
+    let(:cake_category) { create(:category) }
+    let!(:cake) { create(:cake, category: cake_category) }
+    let!(:cookie) { create(:cake) }
+
+    before :each do
+      cake.photos << create(:photo)
+      cookie.photos << create(:photo)
+    end
+
+    it 'returns all cakes in a specific category' do
+      cakes = subject.fetch(category: cake_category.slug)
+      expect(cakes).to include(cake)
+      expect(cakes).to_not include(cookie)
+    end
+  end
+end
spec/services/queries/find_all_creations_query_spec.rb
@@ -1,22 +0,0 @@
-require "rails_helper"
-
-describe FindAllCreationsQuery do
-  subject { FindAllCreationsQuery.new }
-  let(:results) { subject.fetch({}) }
-
-  let!(:cake_with_a_photo) { create(:creation) }
-  let!(:cake_without_a_photo) { create(:creation, photos: []) }
-
-  before :each do
-    cake_with_a_photo.photos << create(:photo)
-    cake_with_a_photo.photos.first.update_attribute(:image_processing, nil)
-  end
-
-  it "returns all creations with at least one photo" do
-    expect(results).to include(cake_with_a_photo)
-  end
-
-  it "ignores cakes without a photo" do
-    expect(results).to_not include(cake_without_a_photo)
-  end
-end