Commit b56289bd by Trong Huu Nguyen

Merge branch 'dhp_solr' into 'development'

[Review] Solr feature

See merge request !5
parents efca5cdb acbd7d6e
...@@ -23,3 +23,6 @@ ...@@ -23,3 +23,6 @@
# Ignore database config file # Ignore database config file
/config/database.yml /config/database.yml
config/settings.local.yml
config/settings/*.local.yml
config/environments/*.local.yml
...@@ -36,6 +36,8 @@ gem 'carrierwave', '~> 1.0' ...@@ -36,6 +36,8 @@ gem 'carrierwave', '~> 1.0'
gem 'mini_magick' gem 'mini_magick'
# bootstrap-sass is a Sass-powered version of Bootstrap 3 # bootstrap-sass is a Sass-powered version of Bootstrap 3
gem 'bootstrap-sass', '~> 3.3.6' gem 'bootstrap-sass', '~> 3.3.6'
# Config helps you easily manage environment specific settings in an easy and usable manner.
gem 'config'
# Faker, a port of Data::Faker from Perl, is used to easily generate fake data: names, addresses, phone numbers, etc. # Faker, a port of Data::Faker from Perl, is used to easily generate fake data: names, addresses, phone numbers, etc.
gem 'faker', '~> 1.6', '>= 1.6.3' gem 'faker', '~> 1.6', '>= 1.6.3'
# Kaminari is a Scope & Engine based, clean, powerful, agnostic, customizable and sophisticated paginator for Rails 4+ # Kaminari is a Scope & Engine based, clean, powerful, agnostic, customizable and sophisticated paginator for Rails 4+
...@@ -58,6 +60,8 @@ gem 'toastr-rails', '~> 1.0', '>= 1.0.3' ...@@ -58,6 +60,8 @@ gem 'toastr-rails', '~> 1.0', '>= 1.0.3'
# (or more often navigation item) # (or more often navigation item)
# is selected based on the current page or other arbitrary condition # is selected based on the current page or other arbitrary condition
gem 'active_link_to', '~> 1.0', '>= 1.0.4' gem 'active_link_to', '~> 1.0', '>= 1.0.4'
# RSolr aims to provide a simple and extensible library for working with Solr
gem 'rsolr', '~> 2.0', '>= 2.0.2'
# Use Capistrano for deployment # Use Capistrano for deployment
# gem 'capistrano-rails', group: :development # gem 'capistrano-rails', group: :development
......
...@@ -76,7 +76,11 @@ GEM ...@@ -76,7 +76,11 @@ GEM
execjs execjs
coffee-script-source (1.12.2) coffee-script-source (1.12.2)
concurrent-ruby (1.0.5) concurrent-ruby (1.0.5)
config (1.4.0)
activesupport (>= 3.0)
deep_merge (~> 1.1.1)
connection_pool (2.2.1) connection_pool (2.2.1)
deep_merge (1.1.1)
devise (4.3.0) devise (4.3.0)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
...@@ -87,6 +91,8 @@ GEM ...@@ -87,6 +91,8 @@ GEM
execjs (2.7.0) execjs (2.7.0)
faker (1.6.6) faker (1.6.6)
i18n (~> 0.5) i18n (~> 0.5)
faraday (0.12.1)
multipart-post (>= 1.2, < 3)
ffi (1.9.18) ffi (1.9.18)
font-awesome-rails (4.7.0.2) font-awesome-rails (4.7.0.2)
railties (>= 3.2, < 5.2) railties (>= 3.2, < 5.2)
...@@ -132,6 +138,7 @@ GEM ...@@ -132,6 +138,7 @@ GEM
mini_portile2 (2.2.0) mini_portile2 (2.2.0)
minitest (5.10.2) minitest (5.10.2)
multi_json (1.12.1) multi_json (1.12.1)
multipart-post (2.0.0)
mysql2 (0.4.6) mysql2 (0.4.6)
nio4r (2.1.0) nio4r (2.1.0)
nokogiri (1.8.0) nokogiri (1.8.0)
...@@ -187,6 +194,9 @@ GEM ...@@ -187,6 +194,9 @@ GEM
responders (2.4.0) responders (2.4.0)
actionpack (>= 4.2.0, < 5.3) actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3) railties (>= 4.2.0, < 5.3)
rsolr (2.0.2)
builder (>= 2.1.2)
faraday
rubocop (0.49.1) rubocop (0.49.1)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0) parser (>= 2.3.3.1, < 3.0)
...@@ -262,6 +272,7 @@ DEPENDENCIES ...@@ -262,6 +272,7 @@ DEPENDENCIES
capybara (~> 2.13) capybara (~> 2.13)
carrierwave (~> 1.0) carrierwave (~> 1.0)
coffee-rails (~> 4.2) coffee-rails (~> 4.2)
config
devise (~> 4.3) devise (~> 4.3)
faker (~> 1.6, >= 1.6.3) faker (~> 1.6, >= 1.6.3)
font-awesome-rails (~> 4.7, >= 4.7.0.2) font-awesome-rails (~> 4.7, >= 4.7.0.2)
...@@ -275,6 +286,7 @@ DEPENDENCIES ...@@ -275,6 +286,7 @@ DEPENDENCIES
puma (~> 3.7) puma (~> 3.7)
rails (~> 5.1.1) rails (~> 5.1.1)
rails-assets-bootstrap-touchspin! rails-assets-bootstrap-touchspin!
rsolr (~> 2.0, >= 2.0.2)
rubocop (~> 0.49.1) rubocop (~> 0.49.1)
sass-rails (~> 5.0) sass-rails (~> 5.0)
selenium-webdriver selenium-webdriver
......
(function($) { (function($) {
// Vertical Spinner - Touchspin - Product Details Quantity input // Vertical Spinner - Touchspin - Product Details Quantity input
if ( $.fn.TouchSpin ) { if ( $.fn.TouchSpin ) {
$('#product_quantity').TouchSpin({ $('.vertical-spinner').TouchSpin({
verticalbuttons: true verticalbuttons: true
}); });
$('.qty-input').TouchSpin(); $('.qty-input').TouchSpin();
......
(function($) { (function($) {
toastr.options.closeButton = true; toastr.options.closeButton = true;
// Search Dropdown Toggle
$('.search-toggle').on('click', function (e) {
$('.header-search-wrapper').toggleClass('open');
e.preventDefault();
});
}).apply(this, [jQuery]); }).apply(this, [jQuery]);
\ No newline at end of file
...@@ -124,11 +124,23 @@ a { ...@@ -124,11 +124,23 @@ a {
clear: both; clear: both;
} }
@media (max-width: 991px) {
#header .header-row {
display: block;
}
}
#header .header-column { #header .header-column {
display: table-cell; display: table-cell;
vertical-align: middle; vertical-align: middle;
} }
@media (max-width: 991px) {
#header .header-column {
display: block;
}
}
#header .header-column .row { #header .header-column .row {
margin: 0; margin: 0;
} }
...@@ -137,6 +149,247 @@ a { ...@@ -137,6 +149,247 @@ a {
display: block; display: block;
clear: right; clear: right;
} }
#header .header-container {
padding-top: 28px;
padding-bottom: 28px;
position: relative;
display: table;
}
#header .header-container.header-nav {
padding: 0;
}
#header .header-nav-main nav {
height: 50px;
border-radius: 0;
background-color: #54555e;
}
#header .header-nav-main nav > ul > li > a.dropdown-toggle {
-webkit-transition: none;
-moz-transition: none;
transition: none;
color: #fff;
padding: 15px 20px 15px 20px;
}
#header .header-nav-main nav > ul > li > a.dropdown-toggle:after {
font-size: inherit;
content: "\f107";
right: 16px;
top: 15px;
}
#header .header-nav-main nav > ul > li > a {
-webkit-transition: none;
-moz-transition: none;
transition: none;
color: #fff;
padding: 15px 20px;
text-transform: uppercase;
}
#header .header-nav-main nav > ul > li:hover > a,
#header .header-nav-main nav > ul > li:hover > a.dropdown-toggle, #header .header-nav-main nav > ul > li.open > a,
#header .header-nav-main nav > ul > li.open > a.dropdown-toggle, #header .header-nav-main nav > ul > li.active > a,
#header .header-nav-main nav > ul > li.active > a.dropdown-toggle, #header .header-nav-main nav > ul > li.dropdown:hover > a,
#header .header-nav-main nav > ul > li.dropdown:hover > a.dropdown-toggle, #header .header-nav-main nav > ul > li.dropdown.open > a,
#header .header-nav-main nav > ul > li.dropdown.open > a.dropdown-toggle, #header .header-nav-main nav > ul > li.dropdown.active > a,
#header .header-nav-main nav > ul > li.dropdown.active > a.dropdown-toggle {
padding-bottom: 19px;
}
#header .header-nav-main nav > ul > li.dropdown .dropdown-menu {
border-left: none;
border-right: none;
border-bottom: none;
}
#header .header-nav-main nav > ul > li.dropdown .dropdown-menu li a {
border-bottom: none;
}
#header .header-nav-main nav > ul > li.dropdown .dropdown-menu li.dropdown-submenu > a:after {
content: "\f105";
font-family: FontAwesome;
font-size: inherit;
border: none;
margin: 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu {
border-radius: 0 0 0 0;
padding: 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content {
padding: 10px 20px 20px;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ul,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ol {
list-style: none;
margin: 0;
padding: 5px 0;
left: 100%;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul li,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol li, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ul li,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ol li {
line-height: 22px;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul li a,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol li a, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ul li a,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ol li a {
padding: 0;
margin: 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul li a:hover, #header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul li a:focus,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol li a:hover,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol li a:focus, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ul li a:hover, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ul li a:focus,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ol li a:hover,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ol li a:focus {
text-decoration: underline;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul li:hover a,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol li:hover a, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ul li:hover a,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content ol li:hover a {
background-color: transparent;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .dropdown-mega-sub-title, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .dropdown-mega-sub-title {
display: block;
font-size: 14px;
font-weight: 600;
padding: 0;
text-transform: uppercase;
line-height: 1.5;
margin-top: 10px;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .cat-img, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .cat-img {
display: block;
padding: 0;
margin-top: 15px;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .cat-img img, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .cat-img img {
display: block;
max-width: 100%;
height: auto;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .dropdown-mega-top, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .dropdown-mega-top {
padding: 4px 0 8px;
border-bottom: 1px solid #eee;
color: #000;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .dropdown-mega-top a,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .dropdown-mega-top span, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .dropdown-mega-top a,
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .dropdown-mega-top span {
font-size: 12px;
font-weight: 400;
color: #000;
text-transform: uppercase;
padding: 0;
margin-right: 15px;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .dropdown-mega-top span, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .dropdown-mega-top span {
font-weight: 700;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area {
position: relative;
text-align: center;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area img, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area img {
display: inline-block;
max-width: 100%;
height: auto;
margin: 20px auto 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header {
position: absolute;
top: -35px;
left: -15px;
text-align: left;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header h3, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header h3 {
font-size: 23px;
font-weight: 600;
color: #fff;
background-color: #2e2e2e;
line-height: 1;
padding: 6px 50px 6px 8px;
margin-bottom: 15px;
text-transform: uppercase;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn {
font-size: 13px;
padding: 5px 7px 5px 8px;
color: #fff;
border: 0;
font-size: 13px;
min-width: 109px;
text-align: center;
text-transform: uppercase;
border-radius: 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn:hover, #header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn:focus, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn:hover, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn:focus {
opacity: 0.9;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn i, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area .menu-banner-header .btn i {
margin-left: 4px;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content .menu-banner-area p, #header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu .dropdown-mega-content .menu-banner-area p {
position: absolute;
bottom: 8px;
width: 60%;
text-align: center;
left: 50px;
line-height: 14px;
font-size: 13px;
margin-bottom: 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega-small > .dropdown-menu {
width: 600px;
}
#header .header-nav-main nav > ul > li.dropdown-mega-small .mega-banner-bg img {
position: absolute;
right: 10px;
top: -10px;
height: 273px;
width: auto;
max-width: none;
z-index: -1;
border-radius: 0;
}
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ul li,
#header .header-nav-main nav > ul > li.dropdown-mega > .dropdown-menu .dropdown-mega-content ol li {
line-height: 23px;
}
#header .header-nav-main nav > ul > li:hover > a, #header .header-nav-main nav > ul > li.open > a, #header .header-nav-main nav > ul > li.active > a {
color: #fff;
background-color: #000;
}
#header .header-nav-main nav > ul > li:hover > a:hover, #header .header-nav-main nav > ul > li:hover > a:focus, #header .header-nav-main nav > ul > li.open > a:hover, #header .header-nav-main nav > ul > li.open > a:focus, #header .header-nav-main nav > ul > li.active > a:hover, #header .header-nav-main nav > ul > li.active > a:focus {
color: #fff;
background-color: #000;
}
#header .header-nav-main nav > ul > li .dropdown-menu > li:hover > a {
background-color: #f4f4f4;
}
#header .header-nav-main nav > ul > li .dropdown-menu > li:hover > a:hover, #header .header-nav-main nav > ul > li .dropdown-menu > li:hover > a:focus {
background-color: #f4f4f4;
}
@media (min-width: 992px) {
#header .header-nav {
display: block !important;
}
#header .header-nav-main {
margin-top: 0;
float: none;
min-height: 54px;
border-bottom: 4px solid #3f4048;
}
}
#header .header-container.header-nav {
padding: 0;
}
@media (max-width: 991px) {
#header .header-container {
display: block;
}
#header .header-nav, #header .header-nav-main {
display: none;
}
}
#header .cart-area { #header .cart-area {
float: right; float: right;
...@@ -623,7 +876,7 @@ a { ...@@ -623,7 +876,7 @@ a {
text-decoration: none; text-decoration: none;
} }
.product-actions a.addtocart { .product-actions .addtocart {
color: #333; color: #333;
background-color: #fff; background-color: #fff;
font-size: 14px; font-size: 14px;
...@@ -633,88 +886,17 @@ a { ...@@ -633,88 +886,17 @@ a {
border: 1px solid #ccc; border: 1px solid #ccc;
} }
.product-actions a.addtocart i { .product-actions .addtocart i {
font-size: 15px; font-size: 15px;
margin-right: 2px; margin-right: 2px;
} }
.product:hover .product-actions a.addtocart { .product:hover .product-actions .addtocart {
background-color: #000; background-color: #000;
border-color: #000; border-color: #000;
color: #fff; color: #fff;
} }
.product-actions a.addtocart.outofstock {
padding: 0 10px;
cursor: default;
}
.product:hover .product-actions a.addtocart.outofstock {
color: #333 !important;
background-color: #fff !important;
border-color: #ccc !important;
}
.product-actions a.addtowishlist, .product-actions a.comparelink, .product-actions a.quickview {
font-size: 17px;
height: 32px;
width: 32px;
line-height: 32px;
background-color: transparent;
visibility: hidden;
opacity: 0;
}
.hide-addtolinks .product-actions a.addtowishlist, .hide-addtolinks .product-actions a.comparelink, .hide-addtolinks .product-actions a.quickview {
display: none;
}
.product-actions a.addtowishlist {
right: -37px;
color: #ed4949;
border: 1px solid #ed4949;
}
.product-actions a.addtowishlist:hover {
color: #fff;
background-color: #ed4949;
}
.product:hover .product-actions a.addtowishlist {
visibility: visible;
opacity: 1;
right: 0;
}
.product-actions a.comparelink {
left: -37px;
color: #52b9b5;
border: 1px solid #52b9b5;
}
.product-actions a.comparelink:hover {
color: #fff;
background-color: #52b9b5;
}
.product:hover .product-actions a.comparelink {
visibility: visible;
opacity: 1;
left: 0;
}
.product-actions a.quickview {
visibility: visible;
opacity: 1;
color: #000;
border: 1px solid #000;
}
.product-actions a.quickview:hover {
color: #fff;
background-color: #000;
}
.product.product-list:after { .product.product-list:after {
content: ''; content: '';
display: table; display: table;
......
...@@ -92,15 +92,6 @@ html .btn-primary:active:focus { ...@@ -92,15 +92,6 @@ html .btn-primary:active:focus {
#header .header-logo img { #header .header-logo img {
margin: 0 24px 0 0; margin: 0 24px 0 0;
} }
#header .header-container {
padding-top: 28px;
padding-bottom: 28px;
position: relative;
display: table;
}
#header .header-container.header-nav {
padding: 0;
}
#header .cart-area { #header .cart-area {
float: right; float: right;
vertical-align: middle; vertical-align: middle;
...@@ -171,7 +162,6 @@ header .header-search { ...@@ -171,7 +162,6 @@ header .header-search {
position: relative; position: relative;
width: 100%; width: 100%;
min-width: 250px; min-width: 250px;
padding-right: 170px;
background-color: #fff; background-color: #fff;
} }
#header .header-search .header-search-wrapper.open { #header .header-search .header-search-wrapper.open {
...@@ -278,6 +268,9 @@ header .header-search { ...@@ -278,6 +268,9 @@ header .header-search {
color: #000; color: #000;
background-color: transparent; background-color: transparent;
} }
#header .header-nav-main nav > ul > li > a {
border-radius: 0;
}
.panel-default>.panel-heading { .panel-default>.panel-heading {
color: #333; color: #333;
background-color: #f5f5f5; background-color: #f5f5f5;
......
class SearchController < ApplicationController
before_action :set_search_result, only: :show
# GET /search
def show
@products = if @search_result.is_a?(Array)
Kaminari.paginate_array(@search_result).page(params[:page]).per(5)
else
@search_result.page(params[:page]).per(5)
end
end
private
def set_search_result
@search_result = if params[:q].present?
Search.new(params[:q]).products
else
Product.all
end
end
end
\ No newline at end of file
class StaticPagesController < ApplicationController class StaticPagesController < ApplicationController
def index def index
@latest_products = Product.page(params[:page]).per(10) @latest_products = Product.page(params[:page]).per(5)
# @TODO: Get recommended products # @TODO: Get recommended products
@recommended_products = Product.last(6) @recommended_products = Product.last(6)
# session.clear # session.clear
......
module SearchHelper
def render_search_result(search_result)
if search_result.blank?
render html: 'Sorry! There are no products matched your query'
else
render(partial: 'products/product_list',
locals: { products: search_result })
end
end
end
\ No newline at end of file
...@@ -16,7 +16,7 @@ class Cart ...@@ -16,7 +16,7 @@ class Cart
real_quantity = product_quantity(product_id, quantity) real_quantity = product_quantity(product_id, quantity)
return false unless product_is_in_stock?(product_id, real_quantity) return false unless product_is_in_stock?(product_id, real_quantity)
if product_item_exist?(product_id) if product_item_exist?(product_id)
@cart[product_id.to_s][:quantity.to_s] += real_quantity.to_i @cart[product_id.to_s][:quantity.to_s] = real_quantity.to_i
else else
@cart[product_id.to_s] = { quantity: real_quantity.to_i } @cart[product_id.to_s] = { quantity: real_quantity.to_i }
end end
......
class Search
def initialize(search_query)
@solr = SolrSearch.new
@search_query = search_query
end
def products
@solr.search_for(@search_query)
filter_products(@solr.docs)
end
private
def filter_products(products)
product_ids = products.map { |product| product[:id.to_s] }
Product.find(product_ids)
end
end
\ No newline at end of file
require 'rsolr'
class SolrSearch
attr_accessor :rsolr
def initialize
@rsolr = RSolr.connect url: Settings.rsolr.address
@response = nil
end
def search_for(search_query)
search_query ||= ''
@response = rsolr.get 'select', params: { q: sanitize_query(search_query) }
end
def docs
@response['response']['docs']
end
def sanitize_query(query)
query.gsub(/[^0-9A-Za-z]/, '')
end
end
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<td class="product-image-td"></td> <td class="product-image-td"></td>
<td class="product-name-td"> <td class="product-name-td">
<h2 class="product-name"> <h2 class="product-name">
<%= link_to product_item[:product].title, product_item_url(product_item[:product]) %> <%= link_to product_item[:product].title, product_url(product_item[:product]) %>
</h2> </h2>
</td> </td>
<td><%= number_to_currency(product_item[:product].price) %></td> <td><%= number_to_currency(product_item[:product].price) %></td>
......
...@@ -36,15 +36,11 @@ ...@@ -36,15 +36,11 @@
</a> </a>
</div> </div>
</div> </div>
<div class="header-search"> <%= render 'layouts/header/search_form' %>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <%= render 'layouts/header/main_nav' %>
<div class="header-container header-nav">
</div>
</div> </div>
</header> </header>
\ No newline at end of file
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_link_tag 'https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800%7CShadows+Into+Light' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head> </head>
......
<div class="header-container header-nav">
<div class="container">
<div class="header-nav-main">
<nav>
<ul id="mainNav" class="nav nav-pills">
<%= active_link_to 'Home', root_url, wrap_tag: :li, active: :exclusive %>
</ul>
</nav>
</div>
</div>
</div>
\ No newline at end of file
<div class="header-search">
<a href="#" class="search-toggle"><i class="fa fa-search"></i></a>
<%= form_tag search_result_path, method: :get do %>
<div class="header-search-wrapper">
<%= text_field_tag :q, params[:q], class: 'form-control', placeholder: 'Search...' %>
<%= button_tag raw('<i class="fa fa-search"></i>'), class: 'btn btn-default' %>
</div>
<% end %>
</div>
\ No newline at end of file
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="form-group"> <div class="form-group">
<%= f.label :quantity %> <%= f.label :quantity %>
<%= f.number_field :quantity, class: "form-control" %> <%= f.number_field :quantity, class: "form-control vertical-spinner" %>
</div> </div>
</div> </div>
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
<div class="product-detail-qty"> <div class="product-detail-qty">
<%= number_field_tag :product_quantity, 1, min: 0, class: 'vertical-spinner' %> <%= number_field_tag :product_quantity, 1, min: 0, class: 'vertical-spinner' %>
</div> </div>
<%= submit_tag 'Add to cart', class: 'addtocart' %> <%= button_tag raw(fa_icon('shopping-cart', text: 'Add to cart')), class: 'addtocart' %>
<% end %> <% end %>
</div> </div>
</div> </div>
......
<div class="product-actions">
<%= form_tag cart_add_product_item_path(product.id), remote: true do %>
<%= hidden_field_tag :product_quantity, 1 %>
<%= button_tag fa_icon('shopping-cart', text: 'Add to cart'), class: 'addtocart' %>
<% end %>
</div>
\ No newline at end of file
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<div class="product-price-box"> <div class="product-price-box">
<span class="product-price"><%= number_to_currency(product.price) %></span> <span class="product-price"><%= number_to_currency(product.price) %></span>
</div> </div>
<%= render partial: 'products/product_action', locals: { product: product } %>
</div> </div>
</div> </div>
</li> </li>
......
...@@ -11,11 +11,12 @@ ...@@ -11,11 +11,12 @@
<%= link_to fa_icon('pencil'), edit_product_path(product) if product.belongs_to_user?(current_user) %> <%= link_to fa_icon('pencil'), edit_product_path(product) if product.belongs_to_user?(current_user) %>
</h2> </h2>
<div class="product-short-desc"> <div class="product-short-desc">
<%= product.description %> <%= truncate(product.description, length: 300) %>
</div> </div>
<div class="product-price-box"> <div class="product-price-box">
<span class="product-price"><%= number_to_currency(product.price) %></span> <span class="product-price"><%= number_to_currency(product.price) %></span>
</div> </div>
<%= render partial: 'products/product_action', locals: { product: product } %>
</div> </div>
</div> </div>
</li> </li>
......
<div class="container">
<div class="row">
<div class="col-md-9 col-md-push-3">
<h2 class="h2 heading-primary mt-lg clearfix">
<span>Search result</span>
</h2>
<%= render_search_result(@products) %>
<div class="toolbar-bottom">
<div class="toolbar">
<div class="sorter">
<%= paginate @products, theme: 'bootstrap' %>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-md-pull-9 sidebar shop-sidebar">
<%= render 'shared/sidebar' %>
</div>
</div>
</div>
<tr>
<td><%= link_to "##{product.id}", edit_product_path(product) %></td>
<td class="product-name-td">
<h2 class="product-name">
<%= link_to product.title, product_url(product) %>
</h2>
</td>
<td><%= number_to_currency(product.price) %></td>
<td><%= product.quantity %></td>
<td><%= link_to fa_icon('pencil'), edit_product_path(product) %></td>
</tr>
\ No newline at end of file
<table class="cart-table">
<thead>
<tr>
<th>ID</th>
<th>Product Name</th>
<th>Unit Price</th>
<th>Qty</th>
<th></th>
</tr>
</thead>
<tbody>
<% @products.each do |product| %>
<%= render partial: 'product', locals: { product: product } %>
<% end %>
</tbody>
</table>
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<h2 class="h2 heading-primary font-weight-normal"> <h2 class="h2 heading-primary font-weight-normal">
My Products My Products
</h2> </h2>
<%= render partial: 'products/product_list', locals: { products: @products } %> <%= render 'product_table' %>
<div class="toolbar-bottom"> <div class="toolbar-bottom">
<div class="toolbar"> <div class="toolbar">
<div class="sorter"> <div class="sorter">
......
Config.setup do |config|
# Name of the constant exposing loaded settings
config.const_name = 'Settings'
# Ability to remove elements of the array set in earlier loaded settings file. For example value: '--'.
#
# config.knockout_prefix = nil
# Overwrite arrays found in previously loaded settings file. When set to `false`, arrays will be merged.
#
# config.overwrite_arrays = true
# Load environment variables from the `ENV` object and override any settings defined in files.
#
# config.use_env = false
# Define ENV variable prefix deciding which variables to load into config.
#
# config.env_prefix = 'Settings'
# What string to use as level separator for settings loaded from ENV variables. Default value of '.' works well
# with Heroku, but you might want to change it for example for '__' to easy override settings from command line, where
# using dots in variable names might not be allowed (eg. Bash).
#
# config.env_separator = '.'
# Ability to process variables names:
# * nil - no change
# * :downcase - convert to lower case
#
# config.env_converter = :downcase
# Parse numeric values as integers instead of strings.
#
# config.env_parse_values = true
end
...@@ -20,4 +20,5 @@ Rails.application.routes.draw do ...@@ -20,4 +20,5 @@ Rails.application.routes.draw do
get '/', to: 'users#show', as: 'user_profile' get '/', to: 'users#show', as: 'user_profile'
get '/products', to: 'users#products', as: 'user_products' get '/products', to: 'users#products', as: 'user_products'
end end
get '/search', to: 'search#show', as: 'search_result'
end end
# RSolr
rsolr:
address: http://localhost:8983/solr/dhp_venshop
\ No newline at end of file
namespace :import_solr_data do
desc "Import product data from database"
task product: :environment do
documents = []
Product.all.each do |product|
documents << { id: product.id, title: product.title, price: product.price }
end
solr_search = SolrSearch.new
solr_search.rsolr.add documents
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment