Navigate the store - view, search, and filter products.

Show list of all categories

In the shop.py, get all categories by calling Category.find_all() method.

camerastore_shop.rb


categories = Category.find_all

Now, the model contains a list all the categories in the camera store, this list encapsulated in Page object.

Page object is a container which wrap a collection of objects, it extends Array so you can iterate over its content using the standard for loop, and can be easily used within erb templates.

We will use this collection of Category objects to populate the top navigation menu of the store.

camerastore/views/layout.erb


<ul class="nav navbar-nav" id="category_menu">
    <li><a href="/products" >All</a></li>
    <% for cat in categories %>
    <% if cat.name != 'Uncategorized' %>
    <li><a href="/categories/<%= cat.id %>" ><%= cat.title %></a></li>
    <% end %>
    <% end %>
    <li><a href="#" id="show_search_box"><span class="glyphicon glyphicon-search"></span></a></li>
</ul>

Display list of all brands

Using the same technique, We can get a list of the available brands, and display them in the sidebar navigation. for example in the details action method:

camerastore_shop.rb


brands = Brand.find_all

Then display it in the sidebar

camerastore/views/products_layout.erb


<h2>Browse By Brand</h2>
<ul class="product-list">
    <% for brand in brands %>
    <li><a href="/brands/<%= brand.id %>"><%= brand.title %></a></li>
    <% end %>
</ul>

Browse products

Likewise, We can obtain and show a list of all products.

camerastore_shop.rb


get '/products' do
  products =  Product.find_all
  brands =  Brand.find_all
  categories =  Category.find_all
  featured =  Collection.find_one(name: 'featured')
  erb :products_layout, layout: :layout, locals: {categories: categories, brands: brands, featured: featured, cart: ShoppingCart.get }do
    erb :products, locals: {products: products, featured: featured}, views: 'views/shop', layout_options: { views: 'views' }
  end
end

To show the products, iterate over the product collection

camerastore/views/shop/products.erb


<ul>
<% for p in products %>
    <li>
        <div>
            <a class="cbp-vm-image" href="/products/<%= p.id %>">
                <div class="simpleCart_shelfItem">
                    <div class="view view-first">
                        <div class="inner_content clearfix">
                            <div class="product_image">
                                <img src="<%= p.mainPhoto.url%>" class="img-responsive" alt=""/>
                                <div class="mask">
                                    <div class="info">Quick View</div>
                                </div>
                                <div class="product_container">
                                    <div class="cart-left">
                                        <p class="title"><%= p.title %></p>
                                    </div>
                                    <div class="pricey"><span class="item_price" >$ <%= p.price %></span></div>
                                    <div class="clearfix"></div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </a>

            <div class="cbp-vm-details">
                <%= p.shortDescription %>
            </div>
            <a class="cbp-vm-icon cbp-vm-add item_add add_to_cart_button"
               data-product_id="<%=p.id%>" href="#">Add to cart</a>
        </div>
    </li>
<% end %>

</ul>

This may looks very boring and repetitive, but we want to make a point out of that: the Java SDK has a very consistent, once you learned a small subset you ‘ll find the rest of it very familiar and predectable.

Searching

Searching for a certain product(s) require a very little code change. Just pass the property you want to search with to the find_all method.

camerastore_shop.rb


get '/products' do
  if params.has_key? 'query'
    products =  Product.find_all(title: params['query'])
  else
    products =  Product.find_all
  end
  brands =  Brand.find_all
  categories =  Category.find_all
  featured =  Collection.find_one(name: 'featured')
  erb :products_layout, layout: :layout, locals: {categories: categories, brands: brands, featured: featured, cart: ShoppingCart.get }do
    erb :products, locals: {products: products, featured: featured}, views: 'views/shop', layout_options: { views: 'views' }
  end
end

Filter products by category

Now, Let’s see how to filter this list of products by category

Because filtering products by category and brand are frequently used operations, there is a dedicated methods for these operations: find_all_by_category and find_all_by_brand respectively.

All find_all* methods return Page object wrapping the result set, so it is possible to use the same view template to display the search results.

camerastore_shop.rb


get '/categories/:id' do
  brands =  Brand.find_all
  categories =  Category.find_all
  products =  Product.find_all(category: params['id'])
  featured =  Collection.find_one(name: 'featured')
  erb :products_layout, layout: :layout, locals: {categories: categories, brands: brands, featured: featured, cart:  ShoppingCart.get }do
    erb :products, views: 'views/shop', layout_options: { views: 'views' }, locals: {products: products, featured: featured}
  end
end

Filter products by brand

Likewise, You can filter products by brand, just use the Product#find_all_by_brand instead.

camerastore_shop.rb


get '/brands/:id' do
  brands =  Brand.find_all
  categories =  Category.find_all
  products =  Product.find_all(brand: params['id'])
  featured =  Collection.find_one(name: 'featured')
  erb :products_layout, layout: :layout, locals: {categories: categories, brands: brands, featured: featured, cart:  ShoppingCart.get}do
    erb :products, views: 'views/shop', layout_options: { views: 'views' }, locals: {products: products, featured: featured}
  end
end

Viewing product details

You can get single product by its ID, just use Product#find_by_id, the code is straightforward:

camerastore_shop.py


get '/products/:id' do
  brands =  Brand.find_all
  categories =  Category.find_all
  product =  Product.find_by_id(params['id'])
  featured =  Collection.find_one(name: 'featured')
  erb :products_layout, layout: :layout, locals: {categories: categories, brands: brands, featured: featured, cart: ShoppingCart.get} do
    erb :single, locals: {product: product}, views: 'views/shop', layout_options: { views: 'views' }
  end
end

And this is the view template:

camerastore/views/shop/single.erb


<div class="new-product">
	<div class="col-md-5 zoom-grid">
		<div class="flexslider">
			<ul class="slides">
				<% for ph in product.photos %>
					<li data-thumb="<%=ph.url%>">
						<div class="thumb-image">
						  <img src="<%=ph.url%>" data-imagezoom="true" class="img-responsive" alt="" />
						</div>
					</li>
				<% end %>
			</ul>
		</div>
	</div>
	<div class="col-md-7 dress-info">
		<div class="dress-name">
			<h3><%= product.title %></h3>
			<span>$ <%= product.price %></span>
			<div class="clearfix"></div>
			<p><%= product.description %></p>

		</div>

		<div class="purchase">
			<a class="cbp-vm-icon cbp-vm-add item_add add_to_cart_button" href="#"
			   data-product_id="<%= product.id %>">Add To Cart</a>
		</div>
    </div>
</div>

Getting Collections

For the sake of completeness, we demonstrate how to get and display Collections, Also this is a good opportunity to show you how you can use Collections in your own projects.

camerastore_shop.rb


get '/' do
  categories = Category.find_all
  collections = Collection.find_all
  erb :index, locals: {categories: categories, collections: collections, cart:  ShoppingCart.get}, views: 'views/shop', layout_options: { views: 'views' }
end

In the home-page of the store, we use Collections to show customers selected collections of our products. We use collection for the available deals, another for the featured products, and one for the newly added products.

camerastore/views/shop/index.html


<% for coll in collections %>
<div class="container collections" >
    <h3 class="like text-center"><%= coll.title %></h3>
    <ul id="<%= coll.name %>" class="flexiselDemo3">
        <% for p in coll.products %>
        <li>
            <a href="/products/<%= p.id %>">
                <img src="<%=p.mainPhoto.url%>" class="img-responsive" alt="" />
            </a>
            <div class="product liked-product simpleCart_shelfItem">
                <a class="like_name" href="/products/<%= p.id %>"><%= p.title %></a>
                <p><a class="item_add add_to_cart_button"
                      data-product_id="<%= p.id %>"><i></i>
                       <span class=" item_price">$ <%= p.price %></span>
                    </a></p>
            </div>
        </li>
        <% end %>
    </ul>
</div>
<% end %>

You can get single collection by name, use Collection#find_by_name

camerastore_shop.rb


get '/products/:id' do
  brands =  Brand.find_all
  categories =  Category.find_all
  product =  Product.find_by_id(params['id'])
  featured =  Collection.find_one(name: 'featured')
  erb :products_layout, layout: :layout, locals: {categories: categories, brands: brands, featured: featured, cart: ShoppingCart.get} do
    erb :single, locals: {product: product}, views: 'views/shop', layout_options: { views: 'views' }
  end
end

We use this in the product details shop/single.erb to show featured products.

camerastore/views/products_layout.erb


<h3 class="like text-center"><%= featured.title %></h3>
<ul id="flexiselDemo3">
    <% for p in featured.products %>
    <li>
        <a href="/products/<%= p.id %>">
            <img src="<%= p.mainPhoto.url %>" style="width: 220px;" class="img-responsive"/>
        </a>
        <div class="product liked-product simpleCart_shelfItem">
            <a class="like_name" href="/products/<%= p.id %>"><%= p.title %></a>
            <p><a class="item_add add_to_cart_button" href="#"
                  data-product_id="<%= p.id %>"><i></i>
                  <span class=" item_price">$ <%= p.price %></span></a></p>
        </div>
    </li>
    <% end %>
</ul>