Commit 85209882 by Truong Ba Dieu

refactor model - service - controller v1

parent 9a93a645
...@@ -61,6 +61,7 @@ gem 'draper', '~> 1.3' # decorator gem ...@@ -61,6 +61,7 @@ gem 'draper', '~> 1.3' # decorator gem
gem 'rsolr' gem 'rsolr'
gem 'validates_timeliness', '~> 3.0' gem 'validates_timeliness', '~> 3.0'
gem "pundit" # verify role gem "pundit" # verify role
gem "rolify" # init roles
# admin # admin
gem 'activeadmin', github: 'activeadmin' gem 'activeadmin', github: 'activeadmin'
...@@ -69,6 +70,7 @@ gem 'kaminari', '0.16.3' ...@@ -69,6 +70,7 @@ gem 'kaminari', '0.16.3'
# cron job # cron job
gem 'whenever', :require => false gem 'whenever', :require => false
# upload source # upload source
gem 'capistrano', '~> 3.1.0' gem 'capistrano', '~> 3.1.0'
gem 'capistrano-bundler', '~> 1.1.2' gem 'capistrano-bundler', '~> 1.1.2'
...@@ -76,6 +78,9 @@ gem 'capistrano-rails', '~> 1.1.1' ...@@ -76,6 +78,9 @@ gem 'capistrano-rails', '~> 1.1.1'
gem 'capistrano-rvm', github: "capistrano/rvm" gem 'capistrano-rvm', github: "capistrano/rvm"
group :development, :test do group :development, :test do
gem 'bullet' # check n+1 query
gem "ruby-growl" # support growl bullet
gem 'rspec' gem 'rspec'
gem 'capybara' gem 'capybara'
gem 'factory_girl_rails', '~> 4.4.1' gem 'factory_girl_rails', '~> 4.4.1'
......
...@@ -82,6 +82,9 @@ GEM ...@@ -82,6 +82,9 @@ GEM
thor thor
breadcrumbs_on_rails (2.3.0) breadcrumbs_on_rails (2.3.0)
builder (3.2.2) builder (3.2.2)
bullet (4.14.7)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.9.0)
byebug (5.0.0) byebug (5.0.0)
columnize (= 0.9.0) columnize (= 0.9.0)
capistrano (3.1.0) capistrano (3.1.0)
...@@ -187,6 +190,8 @@ GEM ...@@ -187,6 +190,8 @@ GEM
addressable (~> 2.3) addressable (~> 2.3)
loofah (2.0.2) loofah (2.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
macaddr (1.7.1)
systemu (~> 2.6.2)
mail (2.6.3) mail (2.6.3)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
method_source (0.8.2) method_source (0.8.2)
...@@ -252,6 +257,7 @@ GEM ...@@ -252,6 +257,7 @@ GEM
request_store (1.1.0) request_store (1.1.0)
responders (2.1.0) responders (2.1.0)
railties (>= 4.2.0, < 5) railties (>= 4.2.0, < 5)
rolify (4.0.0)
rsolr (1.0.12) rsolr (1.0.12)
builder (>= 2.1.2) builder (>= 2.1.2)
rspec (3.0.0) rspec (3.0.0)
...@@ -274,6 +280,8 @@ GEM ...@@ -274,6 +280,8 @@ GEM
rspec-mocks (~> 3.0.0) rspec-mocks (~> 3.0.0)
rspec-support (~> 3.0.0) rspec-support (~> 3.0.0)
rspec-support (3.0.4) rspec-support (3.0.4)
ruby-growl (4.1)
uuid (~> 2.3, >= 2.3.5)
rubyzip (1.1.7) rubyzip (1.1.7)
sass (3.4.16) sass (3.4.16)
sass-rails (5.0.3) sass-rails (5.0.3)
...@@ -307,6 +315,7 @@ GEM ...@@ -307,6 +315,7 @@ GEM
colorize (>= 0.7.0) colorize (>= 0.7.0)
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-ssh (>= 2.8.0) net-ssh (>= 2.8.0)
systemu (2.6.5)
temple (0.7.6) temple (0.7.6)
thin (1.6.3) thin (1.6.3)
daemons (~> 1.0, >= 1.0.9) daemons (~> 1.0, >= 1.0.9)
...@@ -326,6 +335,9 @@ GEM ...@@ -326,6 +335,9 @@ GEM
uglifier (2.7.1) uglifier (2.7.1)
execjs (>= 0.3.0) execjs (>= 0.3.0)
json (>= 1.8.0) json (>= 1.8.0)
uniform_notifier (1.9.0)
uuid (2.3.8)
macaddr (~> 1.0)
vacuum (1.3.0) vacuum (1.3.0)
jeff (~> 1.0) jeff (~> 1.0)
multi_xml (~> 0.5.0) multi_xml (~> 0.5.0)
...@@ -353,6 +365,7 @@ DEPENDENCIES ...@@ -353,6 +365,7 @@ DEPENDENCIES
bootstrap-sass (= 3.3.4.1) bootstrap-sass (= 3.3.4.1)
bootstrap3-datetimepicker-rails (~> 4.7.14) bootstrap3-datetimepicker-rails (~> 4.7.14)
breadcrumbs_on_rails breadcrumbs_on_rails
bullet
byebug byebug
capistrano (~> 3.1.0) capistrano (~> 3.1.0)
capistrano-bundler (~> 1.1.2) capistrano-bundler (~> 1.1.2)
...@@ -378,6 +391,7 @@ DEPENDENCIES ...@@ -378,6 +391,7 @@ DEPENDENCIES
pundit pundit
quiet_assets quiet_assets
rails (= 4.2.1) rails (= 4.2.1)
rolify
rsolr rsolr
rspec rspec
rspec-core rspec-core
...@@ -385,6 +399,7 @@ DEPENDENCIES ...@@ -385,6 +399,7 @@ DEPENDENCIES
rspec-mocks rspec-mocks
rspec-rails (~> 3.0.1) rspec-rails (~> 3.0.1)
rspec-support rspec-support
ruby-growl
sass-rails (~> 5.0) sass-rails (~> 5.0)
sdoc (~> 0.4.0) sdoc (~> 0.4.0)
selenium-webdriver selenium-webdriver
......
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
include Pundit include Pundit
include OrderHelper include OrderHelper
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception protect_from_forgery with: :exception
layout :detect_layout layout Proc.new { |controller| controller.devise_controller? ? 'devise' : 'application' }
before_action :configure_permitted_parameters, if: :devise_controller? before_action :configure_permitted_parameters, if: :devise_controller?
# rescue for gem pundit # rescue for gem pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def get_categories add_breadcrumb "Home", :root_path
@categories = Category.all
end
def detect_layout def get_categories
if devise_controller? @categories = Category.featured
"devise"
else
"application"
end
end end
def authenticate_admin_user! def authenticate_admin_user!
authenticate_user! authenticate_user!
unless current_user.admin? unless current_user.has_role?(:admin)
redirect_to root_path, error: "This area is restricted to administrators only." redirect_to root_path, error: "This area is restricted to administrators only."
end end
end end
...@@ -41,4 +35,15 @@ class ApplicationController < ActionController::Base ...@@ -41,4 +35,15 @@ class ApplicationController < ActionController::Base
flash[:notice] = "You are not authorized to perform this action." flash[:notice] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path) redirect_to(request.referrer || root_path)
end end
# result is instance of ResultMessage(type: :notice/:error , content: 'msg')
def redirect_with_notice(path=root_path, result=nil, rescue_path=root_path)
if result.error?
flash[:error] = result.to_s if result.present?
redirect_to rescue_path
else
flash[:notice] = result.to_s if result.present?
redirect_to path
end
end
end end
class CategoriesController < ApplicationController class CategoriesController < ApplicationController
before_action :get_categories before_action :get_categories
add_breadcrumb "Home", :root_path
def show def show
@category = Category.find(params[:id]) @category = Category.find(params[:id])
@products = @category.products.paginate(page: params[:page]) @products = @category.products.paginate(page: params[:page])
......
class HomeController < ApplicationController class HomeController < ApplicationController
add_breadcrumb "Home", :root_path
before_action :authenticate_user!, only: [:cart] before_action :authenticate_user!, only: [:cart]
before_action :get_categories before_action :get_categories
before_action :get_recommend before_action :get_recommend
...@@ -11,7 +9,7 @@ class HomeController < ApplicationController ...@@ -11,7 +9,7 @@ class HomeController < ApplicationController
def search def search
add_breadcrumb "Search" add_breadcrumb "Search"
@solr_products = Product.search_by_keyword(params) @solr_products = Product.solr_search(params)
@products = Product.where(id: @solr_products.map{ |h| h["id"] }) @products = Product.where(id: @solr_products.map{ |h| h["id"] })
end end
......
class OrdersController < ApplicationController class OrdersController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :set_order, only: [:show]
before_action -> { authorize(@order) }, only: [:show]
layout "cart" layout "cart"
def index def index
@orders = current_user.orders.paginate(page: params[:page]) @orders = current_user.orders.order(completed_at: :desc).paginate(page: params[:page])
end end
def update def update
current_order.update_attributes(update_order_params) result = CartService.new(current_order).update_cart(update_order_params)
redirect_to cart_path(), notice: "Update cart successfully" redirect_with_notice(cart_path, result, cart_path)
end end
def add_to_cart def add_to_cart
state = CartService.add_product(current_order, params) result = CartService.new(current_order).add_product(params)
if state[0] == true redirect_with_notice(product_path(params[:product_id]), result)
flash[:notice] = state[1]
else
flash[:error] = state[1]
end
redirect_to product_path(params[:product_id])
end end
def show def show
@order = current_user.orders.find_by_id(params[:id])
redirect_to root_path if @order.blank?
end end
def checkout def checkout
order_id = current_order.id order_id = current_order.id
state = CartService.checkout(current_order) result = CartService.new(current_order).checkout
if state[0] == true redirect_with_notice(root_path(order_id), result, order_path(order_id))
redirect_to order_path(order_id), notice: state[1]
else
redirect_to root_path(order_id), error: state[1]
end
end end
private private
def set_order
@order = Order.find(params[:id])
end
def update_order_params def update_order_params
params.require(:order).permit(line_items_attributes:[:id, :quantity]) params.require(:order).permit(line_items_attributes:[:id, :quantity])
end end
......
...@@ -5,8 +5,6 @@ class ProductsController < ApplicationController ...@@ -5,8 +5,6 @@ class ProductsController < ApplicationController
before_action :authenticate_user!, :only => [:new, :create] before_action :authenticate_user!, :only => [:new, :create]
after_action :verify_authorized, :only => [:new, :create] after_action :verify_authorized, :only => [:new, :create]
add_breadcrumb "Home", :root_path
def show def show
@product = Product.find(params[:id]) @product = Product.find(params[:id])
add_breadcrumb @product.category.try(:name), category_path(@product.category.try(:id)) add_breadcrumb @product.category.try(:name), category_path(@product.category.try(:id))
...@@ -34,8 +32,8 @@ class ProductsController < ApplicationController ...@@ -34,8 +32,8 @@ class ProductsController < ApplicationController
private private
def new_product_params def new_product_params
params[:product][:release_date] = DatetimeService.strptime(params[:product][:release_date], "%m/%d/%Y %H:%M %p") params[:product][:release_date] = Datetime.rstrptime(params[:product][:release_date], "%m/%d/%Y %H:%M %p")
params[:product][:public_date] = DatetimeService.strptime(params[:product][:public_date], "%m/%d/%Y %H:%M %p") params[:product][:public_date] = Datetime.rstrptime(params[:product][:public_date], "%m/%d/%Y %H:%M %p")
params.require(:product).permit(:stock, :pid, :title, :author, :publisher, :studio, :price, :currency, :category_id, :image, :release_date, :public_date, :recommend) params.require(:product).permit(:stock, :pid, :title, :author, :publisher, :studio, :price, :currency, :category_id, :image, :release_date, :public_date, :recommend)
end end
end end
\ No newline at end of file
ActiveRecord::Base.class_eval do
def to_hash(fields)
begin
hash = {}
fields.each do |f|
hash[f.to_sym] = send(f.to_sym)
end
hash
rescue
{}
end
end
end
\ No newline at end of file
DateTime.instance_eval do
def rstrftime(datetime = nil, type="%B %d, %Y", rescue_datetime=nil)
begin
datetime.strftime(type)
rescue # try to strftime rescue_datetime when error
rescue_datetime.strftime(type) if rescue_datetime.is_a?(DateTime) || rescue_datetime.is_a?(Time)
end
end
def rstrptime(str = nil, type="%Y-%m-%d", rescue_time=DateTime.now)
begin
str.strptime(type)
rescue
rescue_time
end
end
end
\ No newline at end of file
...@@ -2,11 +2,18 @@ class OrderDecorator < Draper::Decorator ...@@ -2,11 +2,18 @@ class OrderDecorator < Draper::Decorator
include Draper::LazyHelpers include Draper::LazyHelpers
def pid_link def pid_link
unless !object.cart? if object.cart?
h.content_tag( :i, "Order not checkout" ) h.content_tag( :i, "Order not checkout" )
else else
h.content_tag( :a, object.pid, href: order_path(object.id) ) h.content_tag( :a, object.pid, href: order_path(object.id) )
end end
end
def state_time
if object.checkout?
"#{object.state} (#{DateTime.rstrftime(object.completed_at, '%B %d, %Y %l:%M %p', object.updated_at)})"
else
object.state
end
end end
end end
\ No newline at end of file
...@@ -5,5 +5,9 @@ class ProductDecorator < Draper::Decorator ...@@ -5,5 +5,9 @@ class ProductDecorator < Draper::Decorator
klass = object.stock > 0 ? 'available' : 'out-stock' klass = object.stock > 0 ? 'available' : 'out-stock'
h.content_tag(:b, "(#{object.stock} available)", class: klass) h.content_tag(:b, "(#{object.stock} available)", class: klass)
end end
def title_url
link_to object.title, product_path(object.id)
end
end end
...@@ -2,4 +2,6 @@ class Category < ActiveRecord::Base ...@@ -2,4 +2,6 @@ class Category < ActiveRecord::Base
has_many :products has_many :products
validates :name, presence: true validates :name, presence: true
scope :featured, -> { limit(5) }
end end
require 'rubygems'
require 'rsolr'
module Solr extend ActiveSupport::Concern
included do
after_save :update_solr
before_destroy :remove_solr
def fetch_solr_attr
to_hash(solr_fields)
end
private
def update_solr
if solr_fields_change?
self.class.rsolr.add fetch_solr_attr
self.class.rsolr.commit
end
end
def remove_solr
solr.delete_by_id id
solr.commit
end
def solr_fields
raise NotImplementedError, 'You must implement the solr_fields'
end
def solr_fields_change?
changed.any? {|field| solr_fields.include? field }
end
end
module ClassMethods
def solr_search(params={})
params[:page] ||= 1
keyword = refine_keyword(params[:keyword])
res = rsolr.paginate params[:page], ENV["default_perpage"], 'select', :params => {:q => "*#{keyword}*"}
fetch_result(res)
end
def rsolr
@rsolr ||= RSolr.connect :url => ENV["solr_url"]
end
private
# refine some special chars can not accept from solr
def refine_keyword(keyword="")
%w(+ - && || ! ( ) { } [ ] ^ " ~ * ? : \\).each do |s|
keyword = keyword.gsub(s, " ")
end
keyword
end
def fetch_result(response)
begin
response["response"]["docs"]
rescue
[]
end
end
end
end
\ No newline at end of file
module UserRole extend ActiveSupport::Concern
included do
rolify
ROLES = %w(client admin)
before_save :default_role
def default_role
self.add_role(:user) if self.roles.blank?
end
end
end
\ No newline at end of file
...@@ -11,11 +11,14 @@ class LineItem < ActiveRecord::Base ...@@ -11,11 +11,14 @@ class LineItem < ActiveRecord::Base
private private
def trigger_recalculate def trigger_recalculate
if quantity_changed?
order.recalculate order.recalculate
change_square = quantity - quantity_was change_square = quantity - quantity_was
product.substract_stock(change_square) product.substract_stock(change_square)
end end
end
# validate quantity line_item with product stock
def check_product_stock def check_product_stock
return false if quantity.blank? || product_id.blank? return false if quantity.blank? || product_id.blank?
change_square = quantity - quantity_was change_square = quantity - quantity_was
......
class Order < ActiveRecord::Base class Order < ActiveRecord::Base
enum state: [:cart, :checkout, :shipping, :completed, :refund] enum state: %i(cart checkout shipping completed refund)
has_many :line_items, dependent: :destroy has_many :line_items, dependent: :destroy
belongs_to :user belongs_to :user
...@@ -8,7 +8,7 @@ class Order < ActiveRecord::Base ...@@ -8,7 +8,7 @@ class Order < ActiveRecord::Base
def recalculate def recalculate
count = line_items.sum(:quantity) count = line_items.sum(:quantity)
self.update_columns( self.update_attributes(
item_count: count, item_count: count,
item_total: self.reload.line_items.inject(0) {|sum, item| sum + item.quantity*item.price } item_total: self.reload.line_items.inject(0) {|sum, item| sum + item.quantity*item.price }
) )
...@@ -16,7 +16,7 @@ class Order < ActiveRecord::Base ...@@ -16,7 +16,7 @@ class Order < ActiveRecord::Base
def checkout def checkout
pid = generate_token pid = generate_token
self.update_columns(state: Order.states[:checkout], pid: pid) self.update_attributes(state: Order.states[:checkout], pid: pid, completed_at: DateTime.now)
end end
private private
......
class Product < ActiveRecord::Base class Product < ActiveRecord::Base
include Solr
belongs_to :category belongs_to :category
belongs_to :user belongs_to :user
...@@ -15,27 +17,15 @@ class Product < ActiveRecord::Base ...@@ -15,27 +17,15 @@ class Product < ActiveRecord::Base
scope :recommend, -> { where(recommend: true) } scope :recommend, -> { where(recommend: true) }
after_save :update_solr
before_destroy :remove_solr
def self.search_by_keyword(params)
SolrService.search(params)
end
def can_buy?(quantity) def can_buy?(quantity)
stock >= quantity.to_i stock >= quantity.to_i
end end
def substract_stock(change) def substract_stock(change)
self.update_columns(stock: stock - change) self.update_attributes(stock: stock - change)
end
private
def update_solr
SolrService.add({id: id, title: title})
end end
def remove_solr def solr_fields
SolrService.remove(id: id) %w(id title)
end end
end end
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
end
class User < ActiveRecord::Base class User < ActiveRecord::Base
include UserRole
# Include default devise modules. Others available are: # Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable # :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, devise :database_authenticatable, :registerable,
...@@ -9,5 +11,4 @@ class User < ActiveRecord::Base ...@@ -9,5 +11,4 @@ class User < ActiveRecord::Base
validates :name, presence: true validates :name, presence: true
enum role: [:client, :admin]
end end
class OrderPolicy < ApplicationPolicy
def show?
user.present? && record.user_id == user.id
end
end
\ No newline at end of file
class CartService class CartService
def initialize(order)
@order = order
end
attr_reader :order
def self.add_product(current_order, params) def add_product(params)
params[:quantity] ||= 1 params[:quantity] ||= 1
product = Product.find(params[:product_id]) product = ::Product.find(params[:product_id])
if product.can_buy?(params[:quantity]) if product.can_buy?(params[:quantity])
line_item = current_order.line_items.where(product_id: product.id, price: product.price).first_or_create line_item = order.line_items.where(product_id: product.id, price: product.price).first_or_create
line_item.quantity += params[:quantity].to_i line_item.quantity += params[:quantity].to_i
if line_item.save if line_item.save
return true, "Add to cart successfully" ResultMessage.new({ type: :notice, content: "Add to cart successfully"})
else else
return false, "Something went wrong" ResultMessage.new({ type: :error, content: "Something went wrong"})
end end
else else
return false, "Product is not enough in stock" ResultMessage.new({ type: :error, content: "Product is not enough in stock"})
end end
end end
def self.checkout(current_order) def checkout
if current_order.line_items.blank? if order.line_items.blank?
return false, "Your cart is empty." ResultMessage.new({ type: :error, content: "Your cart is empty"})
else else
current_order.checkout if order.checkout
UserMailer.success_checkout(current_order).deliver UserMailer.success_checkout(order).deliver
return true, "Checkout successfully" ResultMessage.new({ type: :notice, content: "Checkout successfully"})
else
ResultMessage.new({ type: :error, content: "Checkout fail. #{order.errors.full_messages.join(', ')}"})
end
end end
end end
def self.update_cart(current_order, params) def update_cart(params)
if current_order.update_attributes(params) if order.update_attributes(params)
return true, "Update cart successfully" ResultMessage.new({ type: :notice, content: "Update cart successfully"})
else else
return false, "Something went wrong" ResultMessage.new({ type: :error, content: "Update cart fail. #{order.errors.full_messages.join(', ')}"})
end end
end end
end end
\ No newline at end of file
class CronjobService class CronjobService
def initialize(options={})
@vaccum = options.fetch(:vaccum, VacuumAwsService.new)
@klass = options[:klass]
end
attr_reader :vaccum, :klass
def self.update_product_price # fields is array str
::Product.find_each do |product| def update(fields=[])
aws_product = VacuumAwsService.item_lookup(item_id: product.pid) @klass.find_each do |object|
product.update_columns(price: aws_product[:price]) if aws_product.present? aws_object = vaccum.item_lookup(item_id: object.pid)
aws_object = vaccum.to_attr(aws_object)
if aws_object.present?
attributes = aws_object.select{|key, value| fields.include?(key.to_s) }
object.update_attributes(attributes)
end
end end
end end
......
class DatetimeService
def self.strptime(str = nil, type="%Y-%m-%d")
begin
DateTime.strptime(str, type)
rescue
DateTime.now
end
end
end
\ No newline at end of file
require 'rubygems'
require 'rsolr'
class SolrService
def self.search(params={})
params[:page] ||= 1
keyword = params[:keyword] || ""
['+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '\\'].each do |s|
keyword = keyword.gsub(s, " ")
end
solr = RSolr.connect :url => ENV["solr_url"]
res = solr.paginate params[:page], ENV["default_perpage"], 'select', :params => {:q => "*#{keyword}*"}
res["response"]["docs"]
end
# add or update index to solr
# documents is {}, or [{},{}]
def self.add(documents)
solr = RSolr.connect :url => ENV["solr_url"]
solr.add documents
solr.commit
end
# delete index solr
# id is num or arr num
def self.remove(ids)
if ids.present?
solr = RSolr.connect :url => ENV["solr_url"]
solr.delete_by_id ids
solr.commit
end
end
end
...@@ -4,4 +4,4 @@ tr ...@@ -4,4 +4,4 @@ tr
td= order.decorate.pid_link td= order.decorate.pid_link
td= order.item_count td= order.item_count
td= order.item_total td= order.item_total
td= order.state td= order.decorate.state_time
\ No newline at end of file \ No newline at end of file
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
- @order.line_items.each_with_index do |item, index| - @order.line_items.each_with_index do |item, index|
tr tr
td= index+1 td= index+1
td= item.product.title td= item.product.decorate.title_url
td= item.quantity td= item.quantity
td= currency_number(item.price, item.product.currency) td= currency_number(item.price, item.product.currency)
td= currency_number(item.price * item.quantity, item.product.currency) td= currency_number(item.price * item.quantity, item.product.currency)
......
require File.expand_path('../boot', __FILE__) require File.expand_path('../boot', __FILE__)
# require 'pry'
require 'rails/all' require 'rails/all'
# Require the gems listed in Gemfile, including any gems # Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production. # you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups) Bundler.require(*Rails.groups)
...@@ -23,6 +24,15 @@ module VenShop ...@@ -23,6 +24,15 @@ module VenShop
# Do not swallow errors in after_commit/after_rollback callbacks. # Do not swallow errors in after_commit/after_rollback callbacks.
config.active_record.raise_in_transactional_callbacks = true config.active_record.raise_in_transactional_callbacks = true
config.autoload_paths += %W(#{config.root}/services) config.autoload_paths += %W(#{config.root}/app/services #{config.root}/lib)
config.to_prepare do
Dir.glob(File.join(File.dirname(__FILE__), "../app/core_extensions/*_extension.rb")) do |c|
# Rails.configuration.cache_classes ? require(c) : load(c)
load(c)
end
end
end end
end end
aws_access_key_id: "AKIAJ77C4CTZOP7TUVWQ" aws_access_key_id: "AKIAIAJR65JO6EIPQWTA"
aws_secret_access_key: "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" aws_secret_access_key: "8rpb5q169RUtj7HU3njH3zxcKthZJmWbgtrzESXy"
associate_tag: "zigexn6400-22" associate_tag: "microv"
solr_url: "http://tomcat:tomcat@localhost:8080/solr/venshop" solr_url: "http://tomcat:tomcat@localhost:8080/solr/venshop"
......
# config valid only for Capistrano 3.1 # config valid only for Capistrano 3.1
lock '3.1.0' lock '3.1.0'
require "whenever/capistrano"
set :application, 'dieutb_venshop' set :application, 'dieutb_venshop'
set :branch, "dev" set :branch, "dev"
set :repo_url, 'git@gitlab.zigexn.vn:dieutb/VenShop.git' set :repo_url, 'git@gitlab.zigexn.vn:dieutb/VenShop.git'
set :whenever_command, "bundle exec whenever"
# Default branch is :master # Default branch is :master
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp } # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }
......
...@@ -31,6 +31,26 @@ Rails.application.configure do ...@@ -31,6 +31,26 @@ Rails.application.configure do
# yet still be able to expire them through the digest params. # yet still be able to expire them through the digest params.
config.assets.digest = true config.assets.digest = true
config.after_initialize do
Bullet.enable = true
Bullet.alert = true
Bullet.bullet_logger = true
Bullet.console = true
# Bullet.growl = true
# Bullet.xmpp = { :account => 'bullets_account@jabber.org',
# :password => 'bullets_password_for_jabber',
# :receiver => 'your_account@jabber.org',
# :show_online_status => true }
Bullet.rails_logger = true
# Bullet.honeybadger = true
Bullet.bugsnag = true
Bullet.airbrake = true
Bullet.rollbar = true
Bullet.add_footer = true
# Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
# Bullet.slack = { webhook_url: 'http://some.slack.url', foo: 'bar' }
end
# Adds additional error checking when serving assets at runtime. # Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies. # Checks for improperly declared sprockets dependencies.
# Raises helpful error messages. # Raises helpful error messages.
......
Rolify.configure do |config|
# By default ORM adapter is ActiveRecord. uncomment to use mongoid
# config.use_mongoid
# Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
# config.use_dynamic_shortcuts
end
\ No newline at end of file
...@@ -9,7 +9,7 @@ set :output, 'log/cron.log' ...@@ -9,7 +9,7 @@ set :output, 'log/cron.log'
set :environment, "production" set :environment, "production"
every 1.hours do every 1.hours do
runner "CronjobService.update_product_price" runner "CronjobService.new({klass: Product}).update(%w(price))"
end end
# every 4.days do # every 4.days do
......
class RolifyCreateRoles < ActiveRecord::Migration
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, :polymorphic => true
t.timestamps
end
create_table(:users_roles, :id => false) do |t|
t.references :user
t.references :role
end
add_index(:roles, :name)
add_index(:roles, [ :name, :resource_type, :resource_id ])
add_index(:users_roles, [ :user_id, :role_id ])
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150722043822) do ActiveRecord::Schema.define(version: 20150728055627) do
create_table "categories", force: :cascade do |t| create_table "categories", force: :cascade do |t|
t.string "name", limit: 255 t.string "name", limit: 255
...@@ -52,6 +52,17 @@ ActiveRecord::Schema.define(version: 20150722043822) do ...@@ -52,6 +52,17 @@ ActiveRecord::Schema.define(version: 20150722043822) do
t.integer "stock", limit: 4, default: 10 t.integer "stock", limit: 4, default: 10
end end
create_table "roles", force: :cascade do |t|
t.string "name", limit: 255
t.integer "resource_id", limit: 4
t.string "resource_type", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
add_index "roles", ["name"], name: "index_roles_on_name", using: :btree
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
t.string "email", limit: 255, default: "", null: false t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false t.string "encrypted_password", limit: 255, default: "", null: false
...@@ -72,4 +83,11 @@ ActiveRecord::Schema.define(version: 20150722043822) do ...@@ -72,4 +83,11 @@ ActiveRecord::Schema.define(version: 20150722043822) do
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "users_roles", id: false, force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "role_id", limit: 4
end
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
end end
...@@ -11,5 +11,4 @@ u = User.find_by(email: "admin@gmail.com") ...@@ -11,5 +11,4 @@ u = User.find_by(email: "admin@gmail.com")
if u.blank? if u.blank?
u = User.create(name: "admin", email: "admin@gmail.com", password: "abc123456") u = User.create(name: "admin", email: "admin@gmail.com", password: "abc123456")
end end
u.role = User.roles[:admin] u.add_role :admin
u.save
\ No newline at end of file
class ResultMessage
def initialize(options={})
@type = options.fetch(:type, :notice)
@content = options[:content]
end
attr_reader :type, :content
def error?
type == :error
end
def to_s
content.to_s
end
end
\ No newline at end of file
...@@ -4,24 +4,20 @@ namespace :crawler do ...@@ -4,24 +4,20 @@ namespace :crawler do
categories = %w(Books Music Electronics Software Kitchen) categories = %w(Books Music Electronics Software Kitchen)
categories.each do |search_cate| categories.each do |search_cate|
category = Category.find_or_create_by(name: search_cate) category = ::Category.find_or_create_by(name: search_cate)
(1..5).each do |page| (1..5).each do |page|
next if category.products.count >= 20 # limit 20 products each category next if category.products.count >= 20 # limit 20 products each category
response = VacuumAwsService.item_search({ vaccum = VacuumAwsService.new
query: { items = vaccum.item_search({
'Keywords' => 'All', 'Keywords' => 'All',
'SearchIndex' => search_cate, 'SearchIndex' => search_cate,
'ItemPage' => page, 'ItemPage' => page
'ResponseGroup' => 'Medium'
}
}) })
items = VacuumAwsService.parse_items(response)
items.each do |item| items.each do |item|
break if category.products.count >= 20 # limit 20 products each category break if category.products.count >= 20 # limit 20 products each category
param_item = VacuumAwsService.parse_item(item) param_item = vaccum.to_attr(item)
if param_item.present? && category.products.where(pid: param_item[:pid], title: param_item[:title]).limit(1).blank? && if param_item.present? && category.products.find_by(pid: param_item[:pid], title: param_item[:title]).blank?
category.products.find_by(title: param_item["title"]).blank?
category.products.create(param_item) category.products.create(param_item)
end end
end end
......
...@@ -19,7 +19,7 @@ module HelperSteps ...@@ -19,7 +19,7 @@ module HelperSteps
step "I go to product page have :amount items in stock" do |amount| step "I go to product page have :amount items in stock" do |amount|
p = ::Product.first p = ::Product.first
p.update_columns(stock: amount) p.update_attributes(stock: amount)
visit product_path(p) visit product_path(p)
end end
......
...@@ -23,7 +23,7 @@ describe Product, :type => :model do ...@@ -23,7 +23,7 @@ describe Product, :type => :model do
it "should return recommend product when call scope recommend" do it "should return recommend product when call scope recommend" do
expect(Product.recommend).to eq [] expect(Product.recommend).to eq []
@product.update_columns(recommend: true) @product.update_attibutes(recommend: true)
expect(Product.recommend).to eq [@product] expect(Product.recommend).to eq [@product]
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