power_shop 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +20 -0
  6. data/README.md +13 -0
  7. data/Rakefile +18 -0
  8. data/app/controllers/catalog_controller.rb +2 -0
  9. data/app/controllers/power_shop/application_controller.rb +13 -0
  10. data/app/controllers/power_shop/cart_controller.rb +53 -0
  11. data/app/controllers/power_shop/catalog_controller.rb +32 -0
  12. data/app/controllers/power_shop/orders_controller.rb +33 -0
  13. data/app/forms/power_shop/order_form.rb +99 -0
  14. data/app/mailers/order_notifications.rb +2 -0
  15. data/app/mailers/power_shop/order_notifications.rb +29 -0
  16. data/app/models/category.rb +4 -0
  17. data/app/models/order.rb +2 -0
  18. data/app/models/order_item.rb +2 -0
  19. data/app/models/power_shop/category.rb +18 -0
  20. data/app/models/power_shop/order.rb +8 -0
  21. data/app/models/power_shop/order_item.rb +9 -0
  22. data/app/models/power_shop/product.rb +45 -0
  23. data/app/models/power_shop/shop_image.rb +8 -0
  24. data/app/models/power_shop/shopping_cart.rb +8 -0
  25. data/app/models/power_shop/shopping_cart_item.rb +6 -0
  26. data/app/models/product.rb +4 -0
  27. data/app/models/shop_image.rb +3 -0
  28. data/app/models/shopping_cart.rb +2 -0
  29. data/app/models/shopping_cart_item.rb +2 -0
  30. data/app/uploaders/power_shop/shop_image_uploader.rb +30 -0
  31. data/app/uploaders/shop_image_uploader.rb +2 -0
  32. data/app/views/power_shop/cart/show.html.erb +0 -0
  33. data/app/views/power_shop/catalog/category.html.erb +0 -0
  34. data/app/views/power_shop/catalog/index.html.erb +2 -0
  35. data/app/views/power_shop/catalog/product.html.erb +0 -0
  36. data/app/views/power_shop/orders/success.html.erb +0 -0
  37. data/config/locales/ru.yml +12 -0
  38. data/config/routes.rb +18 -0
  39. data/db/migrate/20140723131458_create_categories.rb +20 -0
  40. data/db/migrate/20140728071046_create_products.rb +20 -0
  41. data/db/migrate/20140729041407_create_cart.rb +8 -0
  42. data/db/migrate/20140731171009_create_shop_image.rb +13 -0
  43. data/db/migrate/20140804101936_create_friendly_id_slugs.rb +15 -0
  44. data/db/migrate/20140828061402_create_orders.rb +13 -0
  45. data/db/migrate/20140828061556_create_order_items.rb +14 -0
  46. data/lib/generators/power_shop/install/install_generator.rb +20 -0
  47. data/lib/generators/power_shop/install/templates/active_admin/category.rb.erb +43 -0
  48. data/lib/generators/power_shop/install/templates/active_admin/order.rb +50 -0
  49. data/lib/generators/power_shop/install/templates/active_admin/product.rb.erb +64 -0
  50. data/lib/power_shop/engine.rb +27 -0
  51. data/lib/power_shop/middleware/shopping_cart.rb +26 -0
  52. data/lib/power_shop/version.rb +3 -0
  53. data/lib/power_shop.rb +4 -0
  54. data/lib/spec.rake +15 -0
  55. data/lib/tasks/spec.rake +15 -0
  56. data/power_shop.gemspec +45 -0
  57. data/script/rails +7 -0
  58. data/spec/dummy/app/assets/images/.keep +0 -0
  59. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  60. data/spec/dummy/app/mailers/.keep +0 -0
  61. data/spec/dummy/app/models/.keep +0 -0
  62. data/spec/dummy/app/models/concerns/.keep +0 -0
  63. data/spec/dummy/lib/assets/.keep +0 -0
  64. data/spec/dummy/log/.keep +0 -0
  65. metadata +78 -10
  66. data/spec/dummy/log/test.log +0 -85730
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6335081116c802154b40b8007c866b10aede93be
4
- data.tar.gz: 4fea63378bb6f8f2f43deb11b8dbe79d4e7c305a
3
+ metadata.gz: 927a4565c38e1512685b3dfd996f02c190835387
4
+ data.tar.gz: ae853db448b6bfeac215261b925b0877450326cd
5
5
  SHA512:
6
- metadata.gz: d5dd587b70ae60bf179ef9b20dfa235ba6bc282fa11c1992a8dd0fc14b1a845dbbf69b2137548f2a9ffa93eafc1f7f43ce93f6588cf82c1260892c6fdc6bce2d
7
- data.tar.gz: c8822b3ea3cf2fd67387e38fea1f68ad7040e7aaf5f026cc2b33d22eb56b26edf4a52d226c717b084d6df2eb50d8b8e26b0a75b9cf52e75a9b4e098b5ecf3395
6
+ metadata.gz: 38a297f31b3b99cb7d377479793dfb86d595b5f307629cb43a622d525137ffefef102a919591a9ef8e9756bdcfb91b7f1574c70ac3369d99d72fc1a098ac8fe9
7
+ data.tar.gz: 1234305aa80b6489041eb86eed6b1b0c32a6725f3d803fee66edf7364e89c3dbe666590104a7341fe6f6af62df92dbc9fd732b90b43ae455828a60d3c8847d8e
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ Gemfile.lock
2
+ spec/dummy/log/
3
+ tags
4
+ .rvmrc
5
+ /coverage
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Semyon Pupkov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ power_shop
2
+ ==========
3
+
4
+ Simple and flexible Ruby On Rails Ecomerce engine
5
+
6
+ ![build status](https://semaphoreapp.com/api/v1/projects/ebecbf67-1b78-4e5d-9a59-208ad57864f8/217416/shields_badge.png)
7
+ [![Code Climate](https://codeclimate.com/github/artofhuman/power_shop/badges/gpa.svg)](https://codeclimate.com/github/artofhuman/power_shop)
8
+ [![Gem Version](https://badge.fury.io/rb/power_shop.svg)](http://badge.fury.io/rb/power_shop)
9
+
10
+ Requirements
11
+
12
+ 1. CKeditor https://github.com/galetahub/ckeditor (Add gem ckeditor to you Gemfile)
13
+ 2. Rmagick (sudo apt-get install libmagickwand-dev)
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'active_support/deprecation'
8
+ ActiveSupport::Deprecation.silenced = true
9
+
10
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
11
+ load 'rails/tasks/engine.rake'
12
+
13
+ load 'lib/tasks/spec.rake'
14
+
15
+ Bundler::GemHelper.install_tasks
16
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
17
+
18
+ task :default => [:spec]
@@ -0,0 +1,2 @@
1
+ class CatalogController < PowerShop::CatalogController
2
+ end
@@ -0,0 +1,13 @@
1
+ module PowerShop
2
+ class ApplicationController < ::ApplicationController
3
+
4
+ # Public: get cart from middleware
5
+ # TODO: concern for project application controller
6
+ #
7
+ # Returns ShoppingCart
8
+ def cart
9
+ @cart ||= request.env['shopping_cart']
10
+ end
11
+ helper_method :cart
12
+ end
13
+ end
@@ -0,0 +1,53 @@
1
+ module PowerShop
2
+ # Controller represents methods for cart
3
+ class CartController < PowerShop::ApplicationController
4
+
5
+ before_filter :find_product, :only => [:add_product, :delete_product]
6
+ skip_before_filter :verify_authenticity_token
7
+
8
+ # Public: add products to shopping cart
9
+ # if request is simple post redirects back
10
+ # if request is ajax respond with json message
11
+ #
12
+ # Returns text/html or text/json
13
+ def add_product
14
+ cart.add(@product, @product.price, params.fetch(:quantity, 1))
15
+
16
+ if request.xhr?
17
+ render_json_cart
18
+ else
19
+ redirect_to :back
20
+ end
21
+ end
22
+
23
+ def delete_product
24
+ # TODO: 99 - its hack for remove all items :)
25
+ cart.remove(@product, 99)
26
+ redirect_to :back
27
+ end
28
+
29
+ # Pubclic: show cart page
30
+ # TODO: preload associations
31
+ #
32
+ # Returns text/html
33
+ def show
34
+ @cart = cart
35
+ end
36
+
37
+ protected
38
+
39
+ def find_product
40
+ @product = ::Product.find(params[:product_id])
41
+ end
42
+
43
+ # Internal: render json response with cart params
44
+ #
45
+ # Returns text/json
46
+ def render_json_cart
47
+ render :json => {
48
+ total_items: cart.total_unique_items,
49
+ subtotal: cart.subtotal
50
+ }.to_json
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,32 @@
1
+ module PowerShop
2
+ class CatalogController < PowerShop::ApplicationController
3
+ # Public: show all products with pagination
4
+ #
5
+ # Returns: text/html
6
+ def index
7
+ @products = scoped_products.page(params[:page])
8
+ end
9
+
10
+ # Public: show products inside current category
11
+ #
12
+ # Returns: text/html
13
+ def category
14
+ @category = ::Category.friendly.find(params[:id])
15
+ @products = scoped_products.where(category: @category).page(params[:page])
16
+ end
17
+
18
+ # Public: show detail page for product
19
+ #
20
+ # Returns text/html
21
+ def product
22
+ @category = ::Category.friendly.find(params[:category_id])
23
+ @product = scoped_products.friendly.find(params[:id])
24
+ end
25
+
26
+ protected
27
+
28
+ def scoped_products
29
+ ::Product.active.includes(:images, :category)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ module PowerShop
2
+ class OrdersController < PowerShop::ApplicationController
3
+
4
+ # GET: create new order action
5
+ # if order success created, redirect to success page
6
+ #
7
+ # Returns text/html
8
+ def create
9
+ @cart = cart
10
+ @order_form = ::OrderForm.new(@cart, permited_params[:order_form])
11
+
12
+ if @order_form.valid?
13
+ if @order_form.perform
14
+ flash[:order_id] = @order_form.order.id
15
+ return redirect_to power_shop.success_order_url
16
+ end
17
+ end
18
+
19
+ render :template => 'power_shop/cart/show'
20
+ end
21
+
22
+ # GET: show simple page for success message
23
+ #
24
+ # Returns text/html
25
+ def success
26
+ end
27
+
28
+ protected
29
+ def permited_params
30
+ params.permit(order_form: [:user_name, :user_phone, :user_email])
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,99 @@
1
+ # coding: utf-8
2
+
3
+ module PowerShop
4
+ # class represent form for create new order
5
+ # TODO: this class want specs
6
+ class OrderForm
7
+ include ActiveModel::Model
8
+
9
+ attr_accessor :user_name, :user_email, :user_phone, :delivery_address
10
+ attr_reader :cart, :order
11
+
12
+ validates :user_name, :user_phone, presence: true
13
+ validates_email_format_of :user_email, allow_nil: true, allow_blank: true
14
+
15
+ delegate :total, :to => :cart
16
+
17
+ # Public: initialize new order form
18
+ #
19
+ # cart - Shopping cart
20
+ def initialize(cart, attributes={})
21
+ @order = ::Order.new
22
+ @cart = cart
23
+
24
+ apply_attributes(attributes) if attributes.present?
25
+ end
26
+
27
+ # Public: process create new order, clear cart, and sent notifications
28
+ #
29
+ # Example:
30
+ # if @order_form.valid?
31
+ # @order_form.perform
32
+ #
33
+ # Returns boolean
34
+ def perform
35
+ return false unless valid?
36
+
37
+ if result = make_order
38
+ cart.clear
39
+ send_emails
40
+ end
41
+
42
+ result
43
+ end
44
+
45
+ protected
46
+
47
+ def create_order_items
48
+ cart.shopping_cart_items.each do |cart_item|
49
+ order.order_items.create(
50
+ {
51
+ product_id: cart_item.item.id,
52
+ product_title: cart_item.item.name,
53
+ price: cart_item.price,
54
+ quantity: cart_item.quantity
55
+ }
56
+ )
57
+ end
58
+ end
59
+
60
+ def create_order
61
+ not_expected_attributes = ['id', 'created_at', 'updated_at']
62
+ order_attributes = @order.attribute_names.reject do |attr|
63
+ not_expected_attributes.include?(attr)
64
+ end
65
+
66
+ order_attributes.each do |attr|
67
+ order.send("#{attr}=", self.send(attr))
68
+ end
69
+
70
+ order.save!
71
+ end
72
+
73
+ # Internal: it makes order in database
74
+ #
75
+ # Retuurns boolean
76
+ def make_order
77
+ ActiveRecord::Base.transaction do
78
+ create_order
79
+ create_order_items
80
+ end
81
+ rescue
82
+ false
83
+ end
84
+
85
+ def send_emails
86
+ ::OrderNotifications.for_admin(order).deliver
87
+ ::OrderNotifications.for_user(order, user_email).deliver if user_email.present?
88
+ end
89
+
90
+ # Internal: sets form values
91
+ #
92
+ # Returns nothing
93
+ def apply_attributes(attributes)
94
+ attributes.each_pair do |attr, value|
95
+ send("#{attr}=", value)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,2 @@
1
+ class OrderNotifications < PowerShop::OrderNotifications
2
+ end
@@ -0,0 +1,29 @@
1
+ module PowerShop
2
+ class OrderNotifications < ActionMailer::Base
3
+ default from: "from@example.com"
4
+
5
+ def for_admin(order)
6
+ @order = order
7
+ mail(
8
+ to: admin_emails,
9
+ subject: 'На сайте оформлен заказ',
10
+ content_type: "text/html"
11
+ )
12
+ end
13
+
14
+ def for_user(order, user_email)
15
+ @order = order
16
+ mail(
17
+ to: user_email,
18
+ subject: 'Спасибо за заказ',
19
+ content_type: "text/html"
20
+ )
21
+ end
22
+
23
+ protected
24
+
25
+ def admin_emails
26
+ 'admin@example.com'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ class Category < PowerShop::Category
2
+ extend FriendlyId
3
+ friendly_id :name, use: :slugged
4
+ end
@@ -0,0 +1,2 @@
1
+ class Order < PowerShop::Order
2
+ end
@@ -0,0 +1,2 @@
1
+ class OrderItem < PowerShop::OrderItem
2
+ end
@@ -0,0 +1,18 @@
1
+ module PowerShop
2
+ class Category < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ self.table_name = 'categories'
5
+
6
+ acts_as_nested_set
7
+
8
+ has_many :products, :dependent => :destroy,
9
+ class_name: '::Product'
10
+
11
+ has_one :image, :class_name => '::ShopImage', :as => :subject,
12
+ :dependent => :destroy
13
+
14
+ accepts_nested_attributes_for :image, :allow_destroy => true
15
+
16
+ validates :name, presence: true
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ module PowerShop
2
+ class Order < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ self.table_name = 'orders'
5
+
6
+ has_many :order_items, class_name: '::OrderItem'
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module PowerShop
2
+ class OrderItem < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ self.table_name = 'order_items'
5
+
6
+ belongs_to :order, class_name: '::Order'
7
+ belongs_to :product, class_name: '::Product'
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ module PowerShop
2
+ class Product < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ self.table_name = 'products'
5
+
6
+ belongs_to :category, class_name: '::Category'
7
+
8
+ # == Calbacks for calculate active products in category
9
+ after_create :increment_category_count, if: ->(product) { product.active? }
10
+ after_destroy :decrement_category_count, if: ->(product) { product.active? }
11
+ after_update :touch_category_count
12
+
13
+ has_many :images, :class_name => '::ShopImage', :as => :subject,
14
+ :dependent => :destroy
15
+
16
+ accepts_nested_attributes_for :images, :allow_destroy => true
17
+ validates_presence_of :name, :price, :category_id
18
+
19
+ # Public: get only active products
20
+ #
21
+ # Returns ActiveRecord::Relation
22
+ def self.active
23
+ where(active: true)
24
+ end
25
+
26
+ # Public: get first image from images
27
+ #
28
+ # Returns ShopImage
29
+ def main_image
30
+ images.first
31
+ end
32
+
33
+ def increment_category_count
34
+ ::Category.increment_counter :products_count, category_id
35
+ end
36
+
37
+ def decrement_category_count
38
+ ::Category.decrement_counter :products_count, category_id
39
+ end
40
+
41
+ def touch_category_count
42
+ active? ? increment_category_count : decrement_category_count
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ module PowerShop
2
+ class ShopImage < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ self.table_name = 'shop_images'
5
+
6
+ belongs_to :subject, polymorphic: true
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module PowerShop
2
+ class ShoppingCart < ActiveRecord::Base
3
+ acts_as_shopping_cart
4
+ self.table_name = 'shopping_carts'
5
+
6
+ def tax_pct; 0 end
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module PowerShop
2
+ class ShoppingCartItem < ActiveRecord::Base
3
+ acts_as_shopping_cart_item
4
+ self.table_name = 'shopping_cart_items'
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ class Product < PowerShop::Product
2
+ extend FriendlyId
3
+ friendly_id :name, use: :slugged
4
+ end
@@ -0,0 +1,3 @@
1
+ class ShopImage < PowerShop::ShopImage
2
+ mount_uploader :image, ShopImageUploader
3
+ end
@@ -0,0 +1,2 @@
1
+ class ShoppingCart < PowerShop::ShoppingCart
2
+ end
@@ -0,0 +1,2 @@
1
+ class ShoppingCartItem < PowerShop::ShoppingCartItem
2
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module PowerShop
4
+ class ShopImageUploader < CarrierWave::Uploader::Base
5
+
6
+ include CarrierWave::RMagick
7
+
8
+ # Choose what kind of storage to use for this uploader:
9
+ storage :file
10
+ # storage :fog
11
+
12
+ # Override the directory where uploaded files will be stored.
13
+ # This is a sensible default for uploaders that are meant to be mounted:
14
+ def store_dir
15
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
16
+ end
17
+
18
+ version :admin_thumb do
19
+ process :resize_to_limit => [100, 100]
20
+ end
21
+
22
+ version :thumb do
23
+ process :resize_to_limit => [100, 100]
24
+ end
25
+
26
+ def extension_white_list
27
+ %w(jpg jpeg png)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,2 @@
1
+ class ShopImageUploader < PowerShop::ShopImageUploader
2
+ end
File without changes
File without changes
@@ -0,0 +1,2 @@
1
+ <h1>Catalog#index</h1>
2
+ <p>Find me in app/views/power_shop/catalog/index.html.erb</p>
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ ru:
2
+ activerecord:
3
+ models:
4
+ order:
5
+ one: 'Заказ'
6
+ few: 'Заказы'
7
+ many: 'Заказы'
8
+ other: 'Заказы'
9
+ attributes:
10
+ user_name: 'Имя'
11
+ user_email: 'email'
12
+ user_phone: 'телефон'
data/config/routes.rb ADDED
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+ PowerShop::Engine.routes.draw do
3
+ scope 'catalog' do
4
+ get '/:id', to: 'catalog#category', as: 'category'
5
+ get '/:category_id/:id', to: 'catalog#product', as: 'product'
6
+ end
7
+
8
+ get 'catalog', to: 'catalog#index'
9
+
10
+ resource :cart, :only => [:show, :destroy], controller: 'cart' do
11
+ post 'add_product/:product_id' => 'cart#add_product', :as => 'add_product'
12
+ delete 'delete_product/:product_id' => 'cart#delete_product', :as => 'delete_product'
13
+ end
14
+
15
+ resource :order, :only => :create do
16
+ get 'success' => 'orders#success'
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ class CreateCategories < ActiveRecord::Migration
2
+ def change
3
+ create_table :categories do |t|
4
+ t.string :name, null: false
5
+ t.string :slug
6
+ t.integer :parent_id
7
+ t.integer :lft
8
+ t.integer :rgt
9
+ t.integer :depth
10
+ t.text :description
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :categories, :slug, unique: true
16
+ add_index :categories, :rgt
17
+ add_index :categories, :lft
18
+ add_index :categories, :parent_id
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class CreateProducts < ActiveRecord::Migration
2
+ def change
3
+ create_table :products do |t|
4
+ t.belongs_to :category, null: false
5
+ t.boolean :active, default: true
6
+ t.string :name, null: false
7
+ t.string :slug
8
+ t.text :description
9
+ t.float :price, null: false
10
+ t.integer :sort, default: 500
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :products, :slug, unique: true
16
+ add_index :products, :category_id
17
+
18
+ add_column :categories, :products_count, :integer, :default => 0
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ class CreateCart < ActiveRecord::Migration
2
+ def change
3
+ create_table :shopping_carts
4
+ create_table :shopping_cart_items do |t|
5
+ t.shopping_cart_item_fields
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ class CreateShopImage < ActiveRecord::Migration
2
+ def change
3
+ create_table :shop_images do |t|
4
+ t.integer :subject_id, null: false
5
+ t.string :subject_type, null: false
6
+ t.string :image
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :shop_images, :subject_id
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ class CreateFriendlyIdSlugs < ActiveRecord::Migration
2
+ def change
3
+ create_table :friendly_id_slugs do |t|
4
+ t.string :slug, :null => false
5
+ t.integer :sluggable_id, :null => false
6
+ t.string :sluggable_type, :limit => 50
7
+ t.string :scope
8
+ t.datetime :created_at
9
+ end
10
+ add_index :friendly_id_slugs, :sluggable_id
11
+ add_index :friendly_id_slugs, [:slug, :sluggable_type]
12
+ add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true
13
+ add_index :friendly_id_slugs, :sluggable_type
14
+ end
15
+ end