diff --git a/Gemfile b/Gemfile index fba3b4e..170b2ff 100644 --- a/Gemfile +++ b/Gemfile @@ -38,3 +38,27 @@ gem 'spring', group: :development # Use debugger # gem 'debugger', group: [:development, :test] + +#customize gem +gem 'pry', '~> 0.10.0' +gem 'simple_form', '~> 3.0.2' +gem 'bootstrap-sass', '~> 3.2.0.0' +#The bootstrap-sass-rails gem is deprecated starting with version 3.1.0.0. +#gem 'bootstrap-sass-rails', '~> 3.1.0.0' +gem 'will_paginate' , '~> 3.0' +gem 'will_paginate-bootstrap' +gem 'devise' , '~> 3.2' +gem 'carrierwave' +gem 'cocoon', '~> 1.2.6' + +group :developmet, :test do + gem 'guard-livereload' + gem 'annotate', '~> 2.6.5' + gem 'mysql2' +end + + + + + + diff --git a/Gemfile.lock b/Gemfile.lock index 53538d9..cca9cb2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -27,8 +27,23 @@ GEM minitest (~> 5.1) thread_safe (~> 0.1) tzinfo (~> 1.1) + annotate (2.6.5) + activerecord (>= 2.3.0) + rake (>= 0.8.7) arel (5.0.1.20140414130214) + bcrypt (3.1.7) + bootstrap-sass (3.2.0.0) + sass (~> 3.2) builder (3.2.2) + carrierwave (0.10.0) + activemodel (>= 3.2.0) + activesupport (>= 3.2.0) + json (>= 1.7) + mime-types (>= 1.16) + celluloid (0.15.2) + timers (~> 1.1.0) + cocoon (1.2.6) + coderay (1.1.0) coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) @@ -36,9 +51,32 @@ GEM coffee-script-source execjs coffee-script-source (1.7.0) + devise (3.2.4) + bcrypt (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 3.2.6, < 5) + thread_safe (~> 0.1) + warden (~> 1.2.3) + em-websocket (0.5.1) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0.6.0) erubis (2.7.0) + eventmachine (1.0.3) execjs (2.2.0) + ffi (1.9.3) + formatador (0.2.5) + guard (2.6.1) + formatador (>= 0.2.4) + listen (~> 2.7) + lumberjack (~> 1.0) + pry (>= 0.9.12) + thor (>= 0.18.1) + guard-livereload (2.3.0) + em-websocket (~> 0.5) + guard (~> 2.0) + multi_json (~> 1.8) hike (1.2.3) + http_parser.rb (0.6.0) i18n (0.6.9) jbuilder (2.0.8) activesupport (>= 3.0.0, < 5) @@ -47,13 +85,25 @@ GEM railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.1) + listen (2.7.9) + celluloid (>= 0.15.2) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + lumberjack (1.0.9) mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) + method_source (0.8.2) mime-types (1.25.1) minitest (5.3.4) multi_json (1.10.1) + mysql2 (0.3.16) + orm_adapter (0.5.0) polyglot (0.3.5) + pry (0.10.0) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) rack (1.5.2) rack-test (0.6.2) rack (>= 1.0) @@ -73,6 +123,9 @@ GEM rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rake (10.3.2) + rb-fsevent (0.9.4) + rb-inotify (0.9.5) + ffi (>= 0.5.0) rdoc (4.1.1) json (~> 1.4) sass (3.2.19) @@ -84,6 +137,10 @@ GEM sdoc (0.4.0) json (~> 1.8) rdoc (~> 4.0, < 5.0) + simple_form (3.0.2) + actionpack (~> 4.0) + activemodel (~> 4.0) + slop (3.5.0) spring (1.1.3) sprockets (2.11.0) hike (~> 1.2) @@ -98,6 +155,7 @@ GEM thor (0.19.1) thread_safe (0.3.4) tilt (1.4.1) + timers (1.1.0) treetop (1.4.15) polyglot polyglot (>= 0.3.1) @@ -108,18 +166,34 @@ GEM uglifier (2.5.0) execjs (>= 0.3.0) json (>= 1.8.0) + warden (1.2.3) + rack (>= 1.0) + will_paginate (3.0.7) + will_paginate-bootstrap (1.0.1) + will_paginate (>= 3.0.3) PLATFORMS ruby DEPENDENCIES + annotate (~> 2.6.5) + bootstrap-sass (~> 3.2.0.0) + carrierwave + cocoon (~> 1.2.6) coffee-rails (~> 4.0.0) + devise (~> 3.2) + guard-livereload jbuilder (~> 2.0) jquery-rails + mysql2 + pry (~> 0.10.0) rails (= 4.1.0) sass-rails (~> 4.0.3) sdoc (~> 0.4.0) + simple_form (~> 3.0.2) spring sqlite3 turbolinks uglifier (>= 1.3.0) + will_paginate (~> 3.0) + will_paginate-bootstrap diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..180e51f --- /dev/null +++ b/Guardfile @@ -0,0 +1,11 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard 'livereload' do + watch(%r{app/views/.+\.(erb|haml|slim)$}) + watch(%r{app/helpers/.+\.rb}) + watch(%r{public/.+\.(css|js|html)}) + watch(%r{config/locales/.+\.yml}) + # Rails Assets Pipeline + watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html|png|jpg))).*}) { |m| "/assets/#{m[3]}" } +end diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/app/assets/javascripts/admin/jquery_customization.js.erb b/app/assets/javascripts/admin/jquery_customization.js.erb new file mode 100644 index 0000000..c768ba3 --- /dev/null +++ b/app/assets/javascripts/admin/jquery_customization.js.erb @@ -0,0 +1,9 @@ +$(document).on('ready page:load', function(){ + + + $("div.item:first-child").addClass("active"); + + //var tmpl = '
' + + +}); \ No newline at end of file diff --git a/app/assets/javascripts/admin/photos.js.coffee b/app/assets/javascripts/admin/photos.js.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/admin/photos.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/admin/products.js.coffee b/app/assets/javascripts/admin/products.js.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/admin/products.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index d6925fa..4975ace 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -14,3 +14,5 @@ //= require jquery_ujs //= require turbolinks //= require_tree . +//= require bootstrap-sprockets +//= require cocoon diff --git a/app/assets/stylesheets/admin/photos.css.scss b/app/assets/stylesheets/admin/photos.css.scss new file mode 100644 index 0000000..e8d0809 --- /dev/null +++ b/app/assets/stylesheets/admin/photos.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin::photos controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss new file mode 100644 index 0000000..da8969d --- /dev/null +++ b/app/assets/stylesheets/admin/products.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin::products controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/bootstrap_and_customization.css.scss b/app/assets/stylesheets/bootstrap_and_customization.css.scss new file mode 100644 index 0000000..9651712 --- /dev/null +++ b/app/assets/stylesheets/bootstrap_and_customization.css.scss @@ -0,0 +1,28 @@ +@import 'bootstrap'; + + + +.center { + text-align: center; +} + +/* why does this css not work? */ +.img-box img { + width: 100%; + height: 261px; +} + + +.carousel-inner .img-box img{ + width: 100%; + height: 261px; + +} + + +.form-img-box img{ + width: 40px; + height: 40px; + +} + diff --git a/app/controllers/admin/photos_controller.rb b/app/controllers/admin/photos_controller.rb new file mode 100644 index 0000000..6ed8897 --- /dev/null +++ b/app/controllers/admin/photos_controller.rb @@ -0,0 +1,31 @@ +class Admin::PhotosController < ApplicationController + + def new + #@photo = Photo.new + @product = Product.find(params[:product_id]) + @photo = @product.photos.build + end + + def create + #@photo = Photo.new(photo_params) + @product = Product.find(params[:product_id]) + @photo = @product.photos.build(photo_params) + if @photo.save + redirect_to admin_product_path(@product) + end + end + + def index + @photos = Photo.all + end + + + + private + + def photo_params + params.require(:photo).permit(:image) + end + + +end diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb new file mode 100644 index 0000000..1a84230 --- /dev/null +++ b/app/controllers/admin/products_controller.rb @@ -0,0 +1,64 @@ +class Admin::ProductsController < ApplicationController + + #the order is important, you should confirm current_user is exit brfore called admin_required + before_action :authenticate_user! + before_action :admin_required, :except => [:index] + before_action :find_product, :only => [:show, :edit, :update, :destroy] + + + def index + @products = Product.all.order("created_at DESC").paginate(:page => params[:page], :per_page=>20) + end + + def show + @photos = @product.photos + end + + def new + @product = Product.new + @product.photos.build + + end + + def create + @product = Product.new(product_params) + + if @product.save + redirect_to admin_products_path + else + render :new + end + end + + def edit + end + + def update + if @product.update(product_params) + redirect_to admin_products_path + else + render :edit + end + + end + + def destroy + if @product.destroy + redirect_to admin_products_path + end + end + + + + private + + def find_product + @product = Product.find(params[:id]) + end + + def product_params + params.require(:product).permit(:title, :description, :quantity, :photos_attributes => [:id, :image, :_destroy]) + end + + +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e..b3569b5 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,10 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + + + + def admin_required + redirect_to root_path if !current_user.admin? + end end diff --git a/app/helpers/admin/photos_helper.rb b/app/helpers/admin/photos_helper.rb new file mode 100644 index 0000000..d77b10b --- /dev/null +++ b/app/helpers/admin/photos_helper.rb @@ -0,0 +1,2 @@ +module Admin::PhotosHelper +end diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb new file mode 100644 index 0000000..977a242 --- /dev/null +++ b/app/helpers/admin/products_helper.rb @@ -0,0 +1,2 @@ +module Admin::ProductsHelper +end diff --git a/app/models/photo.rb b/app/models/photo.rb new file mode 100644 index 0000000..a08bc39 --- /dev/null +++ b/app/models/photo.rb @@ -0,0 +1,15 @@ +# == Schema Information +# +# Table name: photos +# +# id :integer not null, primary key +# created_at :datetime +# updated_at :datetime +# image :string(255) +# product_id :integer +# + +class Photo < ActiveRecord::Base + mount_uploader :image, ImageUploader + belongs_to :product +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000..bd588c4 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,17 @@ +# == Schema Information +# +# Table name: products +# +# id :integer not null, primary key +# title :string(255) +# description :text +# quantity :integer +# created_at :datetime +# updated_at :datetime +# + +class Product < ActiveRecord::Base + has_many :photos, :dependent => :delete_all + + accepts_nested_attributes_for :photos, :reject_if => :all_blank, allow_destroy: true +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..16ef9c9 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,31 @@ +# == Schema Information +# +# Table name: users +# +# id :integer not null, primary key +# email :string(255) default(""), not null +# encrypted_password :string(255) default(""), not null +# reset_password_token :string(255) +# reset_password_sent_at :datetime +# remember_created_at :datetime +# sign_in_count :integer default(0), not null +# current_sign_in_at :datetime +# last_sign_in_at :datetime +# current_sign_in_ip :string(255) +# last_sign_in_ip :string(255) +# created_at :datetime +# updated_at :datetime +# is_admin :boolean default(FALSE) +# + +class User < ActiveRecord::Base + # Include default devise modules. Others available are: + # :confirmable, :lockable, :timeoutable and :omniauthable + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable + + def admin? + is_admin + end + +end diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb new file mode 100644 index 0000000..2fc27d0 --- /dev/null +++ b/app/uploaders/image_uploader.rb @@ -0,0 +1,51 @@ +# encoding: utf-8 + +class ImageUploader < CarrierWave::Uploader::Base + + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + # include CarrierWave::MiniMagick + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # # For Rails 3.1+ asset pipeline compatibility: + # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) + # + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + # version :thumb do + # process :resize_to_fit => [50, 50] + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + # def extension_white_list + # %w(jpg jpeg gif png) + # end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/views/admin/photos/_form.html.erb b/app/views/admin/photos/_form.html.erb new file mode 100644 index 0000000..a204de8 --- /dev/null +++ b/app/views/admin/photos/_form.html.erb @@ -0,0 +1,9 @@ + + + <%=f.input :image, :input_html=>{:class=>"form-control"}, :wrapper_html=>{:class=>"form-group"}, :label=>"上傳圖片"%> + \ No newline at end of file diff --git a/app/views/admin/photos/index.html.erb b/app/views/admin/photos/index.html.erb new file mode 100644 index 0000000..fbd0fd8 --- /dev/null +++ b/app/views/admin/photos/index.html.erb @@ -0,0 +1,4 @@ +<%= product.title%>
+Welcome <%= @email %>!
+ +You can confirm your account email through the link below:
+ +<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..f667dc1 --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +Hello <%= @resource.email %>!
+ +Someone has requested a link to change your password. You can do this through the link below.
+ +<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
+ +If you didn't request this, please ignore this email.
+Your password won't change until you access the link above and create a new one.
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..41e148b --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +Hello <%= @resource.email %>!
+ +Your account has been locked due to an excessive number of unsuccessful sign in attempts.
+ +Click the link below to unlock your account:
+ +<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 0000000..8f995ed --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,19 @@ +