From 50373ef4f67412e5a9aa7b5a4d687888b6ccf24a Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 9 Jun 2014 20:24:39 +0800 Subject: [PATCH 01/59] 1. add product backend, 2. add product new, index controller and view --- TODO | 11 +++++++++ .../javascripts/admin/products.js.coffee | 3 +++ .../stylesheets/admin/products.css.scss | 3 +++ app/controllers/admin/products_controller.rb | 24 +++++++++++++++++++ app/helpers/admin/products_helper.rb | 2 ++ app/models/product.rb | 2 ++ app/views/admin/products/index.html.erb | 5 ++++ app/views/admin/products/new.html.erb | 17 +++++++++++++ config/routes.rb | 6 +++++ db/migrate/20140609120041_create_products.rb | 11 +++++++++ db/schema.rb | 24 +++++++++++++++++++ .../admin/products_controller_test.rb | 7 ++++++ test/fixtures/products.yml | 11 +++++++++ test/helpers/admin/products_helper_test.rb | 4 ++++ test/models/product_test.rb | 7 ++++++ 15 files changed, 137 insertions(+) create mode 100644 TODO create mode 100644 app/assets/javascripts/admin/products.js.coffee create mode 100644 app/assets/stylesheets/admin/products.css.scss create mode 100644 app/controllers/admin/products_controller.rb create mode 100644 app/helpers/admin/products_helper.rb create mode 100644 app/models/product.rb create mode 100644 app/views/admin/products/index.html.erb create mode 100644 app/views/admin/products/new.html.erb create mode 100644 db/migrate/20140609120041_create_products.rb create mode 100644 db/schema.rb create mode 100644 test/controllers/admin/products_controller_test.rb create mode 100644 test/fixtures/products.yml create mode 100644 test/helpers/admin/products_helper_test.rb create mode 100644 test/models/product_test.rb diff --git a/TODO b/TODO new file mode 100644 index 00000000..a0d69f7e --- /dev/null +++ b/TODO @@ -0,0 +1,11 @@ + ☐ 身為商家的管理者,我要能夠在後台上架我的東西,並設定能夠販賣 + ☐ 管理者必須要有一個後台 + ☐ 後台必須要可以新增產品 + ☐ 產品內容必須要有標題,文字,數量,圖片 + + ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 + ☐ 身為管理者,才可以進入後台 + ☐ 身為管理者,必須要登入且是admin + ☐ 管理者身份必須要被分為admin/user + + diff --git a/app/assets/javascripts/admin/products.js.coffee b/app/assets/javascripts/admin/products.js.coffee new file mode 100644 index 00000000..24f83d18 --- /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/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss new file mode 100644 index 00000000..da8969d1 --- /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/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb new file mode 100644 index 00000000..4ee059fd --- /dev/null +++ b/app/controllers/admin/products_controller.rb @@ -0,0 +1,24 @@ +class Admin::ProductsController < ApplicationController + def index + @products = Product.all + end + + def new + @product = Product.new + end + + def create + @product = Product.new(product_params) + + if @product.save + redirect_to admin_products_path + else + render :new + end + end + + private + def product_params + params.require(:product).permit(:title, :description, :quantity) + end +end diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb new file mode 100644 index 00000000..977a242f --- /dev/null +++ b/app/helpers/admin/products_helper.rb @@ -0,0 +1,2 @@ +module Admin::ProductsHelper +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 00000000..077a8197 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,2 @@ +class Product < ActiveRecord::Base +end diff --git a/app/views/admin/products/index.html.erb b/app/views/admin/products/index.html.erb new file mode 100644 index 00000000..8a709b89 --- /dev/null +++ b/app/views/admin/products/index.html.erb @@ -0,0 +1,5 @@ + diff --git a/app/views/admin/products/new.html.erb b/app/views/admin/products/new.html.erb new file mode 100644 index 00000000..625ac4ac --- /dev/null +++ b/app/views/admin/products/new.html.erb @@ -0,0 +1,17 @@ +<%= form_for [:admin, @product] do |f| %> +
+ <%= f.label("權限") %> + <%= f.text_field :title %> +
+ +
+ <%= f.label("敘述") %> + <%= f.text_area :description %> +
+ +
+ <%= f.label("權限") %> + <%= f.text_field :quantity %> +
+ <%= f.submit "Submit", :disable_with => 'Submiting....' %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 3f66539d..960c5810 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,8 @@ Rails.application.routes.draw do + namespace :admin do + resources :products + end + # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". @@ -53,4 +57,6 @@ # # (app/controllers/admin/products_controller.rb) # resources :products # end + + end diff --git a/db/migrate/20140609120041_create_products.rb b/db/migrate/20140609120041_create_products.rb new file mode 100644 index 00000000..805c9766 --- /dev/null +++ b/db/migrate/20140609120041_create_products.rb @@ -0,0 +1,11 @@ +class CreateProducts < ActiveRecord::Migration + def change + create_table :products do |t| + t.string :title + t.text :description + t.integer :quantity + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 00000000..de172dac --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,24 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20140609120041) do + + create_table "products", force: true do |t| + t.string "title" + t.text "description" + t.integer "quantity" + t.datetime "created_at" + t.datetime "updated_at" + end + +end diff --git a/test/controllers/admin/products_controller_test.rb b/test/controllers/admin/products_controller_test.rb new file mode 100644 index 00000000..508fe6b7 --- /dev/null +++ b/test/controllers/admin/products_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class Admin::ProductsControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/fixtures/products.yml b/test/fixtures/products.yml new file mode 100644 index 00000000..c3b9bc15 --- /dev/null +++ b/test/fixtures/products.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + title: MyString + description: MyText + quantity: 1 + +two: + title: MyString + description: MyText + quantity: 1 diff --git a/test/helpers/admin/products_helper_test.rb b/test/helpers/admin/products_helper_test.rb new file mode 100644 index 00000000..0b696b1f --- /dev/null +++ b/test/helpers/admin/products_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class Admin::ProductsHelperTest < ActionView::TestCase +end diff --git a/test/models/product_test.rb b/test/models/product_test.rb new file mode 100644 index 00000000..211cdd0b --- /dev/null +++ b/test/models/product_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ProductTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From ba4cc71859ae027ba919bce2897e317442a54fef Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 9 Jun 2014 20:26:55 +0800 Subject: [PATCH 02/59] add devise into project --- Gemfile | 1 + Gemfile.lock | 13 + app/models/user.rb | 6 + config/initializers/devise.rb | 258 ++++++++++++++++++ config/locales/devise.en.yml | 60 ++++ config/routes.rb | 1 + db/migrate/20140609122603_devise_create_users | 42 +++ test/fixtures/users.yml | 11 + test/models/user_test.rb | 7 + 9 files changed, 399 insertions(+) create mode 100644 app/models/user.rb create mode 100644 config/initializers/devise.rb create mode 100644 config/locales/devise.en.yml create mode 100644 db/migrate/20140609122603_devise_create_users create mode 100644 test/fixtures/users.yml create mode 100644 test/models/user_test.rb diff --git a/Gemfile b/Gemfile index fba3b4e0..6816d790 100644 --- a/Gemfile +++ b/Gemfile @@ -38,3 +38,4 @@ gem 'spring', group: :development # Use debugger # gem 'debugger', group: [:development, :test] +gem 'devise' diff --git a/Gemfile.lock b/Gemfile.lock index 53538d9b..3c73e9a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -28,6 +28,9 @@ GEM thread_safe (~> 0.1) tzinfo (~> 1.1) arel (5.0.1.20140414130214) + bcrypt (3.1.7) + bcrypt-ruby (3.1.5) + bcrypt (>= 3.1.3) builder (3.2.2) coffee-rails (4.0.1) coffee-script (>= 2.2.0) @@ -36,6 +39,12 @@ GEM coffee-script-source execjs coffee-script-source (1.7.0) + devise (3.1.0) + bcrypt-ruby (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 3.2.6, < 5) + thread_safe (~> 0.1) + warden (~> 1.2.3) erubis (2.7.0) execjs (2.2.0) hike (1.2.3) @@ -53,6 +62,7 @@ GEM mime-types (1.25.1) minitest (5.3.4) multi_json (1.10.1) + orm_adapter (0.5.0) polyglot (0.3.5) rack (1.5.2) rack-test (0.6.2) @@ -108,12 +118,15 @@ GEM uglifier (2.5.0) execjs (>= 0.3.0) json (>= 1.8.0) + warden (1.2.3) + rack (>= 1.0) PLATFORMS ruby DEPENDENCIES coffee-rails (~> 4.0.0) + devise jbuilder (~> 2.0) jquery-rails rails (= 4.1.0) diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 00000000..c8220270 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,6 @@ +class User < ActiveRecord::Base + # Include default devise modules. Others available are: + # :confirmable, :lockable, :timeoutable and :omniauthable + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :trackable, :validatable +end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 00000000..4231307b --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,258 @@ +# Use this hook to configure devise mailer, warden hooks and so forth. +# Many of these configuration options can be set straight in your model. +Devise.setup do |config| + # The secret key used by Devise. Devise uses this key to generate + # random tokens. Changing this key will render invalid all existing + # confirmation, reset password and unlock tokens in the database. + config.secret_key = 'b73208e071daf7f996f2c7e3a2ad65d19cb5f4292fcfa716f654f58d822220b72ceb80f3733ff3e64418fd322e3f63b4fb14ddb0d04cefae1102581a962271bd' + + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in Devise::Mailer, + # note that it will be overwritten if you use your own mailer class + # with default "from" parameter. + config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' + + # Configure the class responsible to send e-mails. + # config.mailer = 'Devise::Mailer' + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating a user. The default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating a user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + # config.authentication_keys = [ :email ] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # Configure which authentication keys should be case-insensitive. + # These keys will be downcased upon creating or modifying a user and when used + # to authenticate or find a user. Default is :email. + config.case_insensitive_keys = [ :email ] + + # Configure which authentication keys should have whitespace stripped. + # These keys will have whitespace before and after removed upon creating or + # modifying a user and when used to authenticate or find a user. Default is :email. + config.strip_whitespace_keys = [ :email ] + + # Tell if authentication through request.params is enabled. True by default. + # It can be set to an array that will enable params authentication only for the + # given strategies, for example, `config.params_authenticatable = [:database]` will + # enable it only for database (email + password) authentication. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Auth is enabled. False by default. + # It can be set to an array that will enable http authentication only for the + # given strategies, for example, `config.http_authenticatable = [:token]` will + # enable it only for token authentication. The supported strategies are: + # :database = Support basic authentication with authentication key + password + # :token = Support basic authentication with token authentication key + # :token_options = Support token authentication with options as defined in + # http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html + # config.http_authenticatable = false + + # If http headers should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. 'Application' by default. + # config.http_authentication_realm = 'Application' + + # It will change confirmation, password recovery and other workflows + # to behave the same regardless if the e-mail provided was right or wrong. + # Does not affect registerable. + # config.paranoid = true + + # By default Devise will store the user in session. You can skip storage for + # :http_auth and :token_auth by adding those symbols to the array below. + # Notice that if you are skipping storage for all authentication paths, you + # may want to disable generating routes to Devise's sessions controller by + # passing :skip => :sessions to `devise_for` in your config/routes.rb + config.skip_session_storage = [:http_auth] + + # By default, Devise cleans up the CSRF token on authentication to + # avoid CSRF token fixation attacks. This means that, when using AJAX + # requests for sign in and sign up, you need to get a new CSRF token + # from the server. You can disable this option at your own risk. + # config.clean_up_csrf_token_on_authentication = true + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 10. If + # using other encryptors, it sets how many times you want the password re-encrypted. + # + # Limiting the stretches to just one in testing will increase the performance of + # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use + # a value less than 10 in other environments. + config.stretches = Rails.env.test? ? 1 : 10 + + # Setup a pepper to generate the encrypted password. + # config.pepper = '1960bcbc1ea2b29b7a7b01b5a48d8c8b15732ee10ed5e39fdf9d48b64585e1d748acd6491e514733b0762ffa278b18883ae1cb2b732b20040a6436be3737d12a' + + # ==> Configuration for :confirmable + # A period that the user is allowed to access the website even without + # confirming his account. For instance, if set to 2.days, the user will be + # able to access the website for two days without confirming his account, + # access will be blocked just in the third day. Default is 0.days, meaning + # the user cannot access the website without confirming his account. + # config.allow_unconfirmed_access_for = 2.days + + # A period that the user is allowed to confirm their account before their + # token becomes invalid. For example, if set to 3.days, the user can confirm + # their account within 3 days after the mail was sent, but on the fourth day + # their account can't be confirmed with the token any more. + # Default is nil, meaning there is no restriction on how long a user can take + # before confirming their account. + # config.confirm_within = 3.days + + # If true, requires any email changes to be confirmed (exactly the same way as + # initial account confirmation) to be applied. Requires additional unconfirmed_email + # db field (see migrations). Until confirmed new email is stored in + # unconfirmed email column, and copied to email column on successful confirmation. + config.reconfirmable = true + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [ :email ] + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # Options to be passed to the created cookie. For instance, you can set + # :secure => true in order to force SSL only cookies. + # config.rememberable_options = {} + + # ==> Configuration for :validatable + # Range for password length. Default is 8..128. + config.password_length = 8..128 + + # Email regex used to validate email formats. It simply asserts that + # one (and only one) @ exists in the given string. This is mainly + # to give user feedback and not to assert the e-mail validity. + # config.email_regexp = /\A[^@]+@[^@]+\z/ + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # If true, expires auth token on session timeout. + # config.expire_auth_token_on_timeout = false + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + # config.lock_strategy = :failed_attempts + + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [ :email ] + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + # config.unlock_strategy = :both + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + # config.maximum_attempts = 20 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [ :email ] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 6.hours + + # ==> Configuration for :encryptable + # Allow you to use another encryption algorithm besides bcrypt (default). You can use + # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, + # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) + # and :restful_authentication_sha1 (then you should set stretches to 10, and copy + # REST_AUTH_SITE_KEY to pepper). + # + # Require the `devise-encryptable` gem when using anything other than bcrypt + # config.encryptor = :sha512 + + # ==> Configuration for :token_authenticatable + # Defines name of the authentication token params key + # config.token_authentication_key = :auth_token + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + # config.scoped_views = false + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). + # config.default_scope = :user + + # Set this configuration to false if you want /users/sign_out to sign out + # only the current scope. By default, Devise signs out all scopes. + # config.sign_out_all_scopes = true + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html, should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. + # + # The "*/*" below is required to match Internet Explorer requests. + # config.navigational_formats = ['*/*', :html] + + # The default HTTP method used to sign out a resource. Default is :delete. + config.sign_out_via = :delete + + # ==> OmniAuth + # Add a new OmniAuth provider. Check the wiki for more information on setting + # up on your models and hooks. + # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' + + # ==> Warden configuration + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. + # + # config.warden do |manager| + # manager.intercept_401 = false + # manager.default_strategies(:scope => :user).unshift :some_external_strategy + # end + + # ==> Mountable engine configurations + # When using Devise inside an engine, let's call it `MyEngine`, and this engine + # is mountable, there are some extra configurations to be taken into account. + # The following options are available, assuming the engine is mounted as: + # + # mount MyEngine, at: '/my_engine' + # + # The router that invoked `devise_for`, in the example above, would be: + # config.router_name = :my_engine + # + # When using omniauth, Devise cannot automatically set Omniauth path, + # so you need to do it manually. For the users scope, it would be: + # config.omniauth_path_prefix = '/my_engine/users/auth' +end diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml new file mode 100644 index 00000000..e7445b31 --- /dev/null +++ b/config/locales/devise.en.yml @@ -0,0 +1,60 @@ +# Additional translations at https://github.com/plataformatec/devise/wiki/I18n + +en: + devise: + confirmations: + confirmed: "Your account was successfully confirmed. Please sign in." + confirmed_and_signed_in: "Your account was successfully confirmed. You are now signed in." + send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes." + failure: + already_authenticated: "You are already signed in." + inactive: "Your account is not activated yet." + invalid: "Invalid email or password." + invalid_token: "Invalid authentication token." + locked: "Your account is locked." + not_found_in_database: "Invalid email or password." + timeout: "Your session expired. Please sign in again to continue." + unauthenticated: "You need to sign in or sign up before continuing." + unconfirmed: "You have to confirm your account before continuing." + mailer: + confirmation_instructions: + subject: "Confirmation instructions" + reset_password_instructions: + subject: "Reset password instructions" + unlock_instructions: + subject: "Unlock Instructions" + omniauth_callbacks: + failure: "Could not authenticate you from %{kind} because \"%{reason}\"." + success: "Successfully authenticated from %{kind} account." + passwords: + no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." + send_instructions: "You will receive an email with instructions about how to reset your password in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." + updated: "Your password was changed successfully. You are now signed in." + updated_not_active: "Your password was changed successfully." + registrations: + destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." + signed_up: "Welcome! You have signed up successfully." + signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." + signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." + signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account." + update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." + updated: "You updated your account successfully." + sessions: + signed_in: "Signed in successfully." + signed_out: "Signed out successfully." + unlocks: + send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." + send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." + unlocked: "Your account has been unlocked successfully. Please sign in to continue." + errors: + messages: + already_confirmed: "was already confirmed, please try signing in" + confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" + expired: "has expired, please request a new one" + not_found: "not found" + not_locked: "was not locked" + not_saved: + one: "1 error prohibited this %{resource} from being saved:" + other: "%{count} errors prohibited this %{resource} from being saved:" diff --git a/config/routes.rb b/config/routes.rb index 960c5810..27c618c3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + devise_for :users namespace :admin do resources :products end diff --git a/db/migrate/20140609122603_devise_create_users b/db/migrate/20140609122603_devise_create_users new file mode 100644 index 00000000..ab71c3d1 --- /dev/null +++ b/db/migrate/20140609122603_devise_create_users @@ -0,0 +1,42 @@ +class DeviseCreateUsers < ActiveRecord::Migration + def change + create_table(:users) do |t| + ## Database authenticatable + t.string :email, :null => false, :default => "" + t.string :encrypted_password, :null => false, :default => "" + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + t.integer :sign_in_count, :default => 0, :null => false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + ## Confirmable + # t.string :confirmation_token + # t.datetime :confirmed_at + # t.datetime :confirmation_sent_at + # t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + + t.timestamps + end + + add_index :users, :email, :unique => true + add_index :users, :reset_password_token, :unique => true + # add_index :users, :confirmation_token, :unique => true + # add_index :users, :unlock_token, :unique => true + end +end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 00000000..937a0c00 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 00000000..82f61e01 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From e20cc2e10c309bb7bc01c3f2c88d025d710dd2e5 Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 9 Jun 2014 20:58:30 +0800 Subject: [PATCH 03/59] 1. add is_admin in user model, 2. add login/logout --- app/controllers/admin/products_controller.rb | 3 +++ app/controllers/application_controller.rb | 4 ++++ app/models/user.rb | 4 ++++ app/views/layouts/application.html.erb | 5 +++++ ... => 20140609122603_devise_create_users.rb} | 0 .../20140609124047_add_is_admin_to_user.rb | 5 +++++ db/schema.rb | 21 ++++++++++++++++++- 7 files changed, 41 insertions(+), 1 deletion(-) rename db/migrate/{20140609122603_devise_create_users => 20140609122603_devise_create_users.rb} (100%) create mode 100644 db/migrate/20140609124047_add_is_admin_to_user.rb diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb index 4ee059fd..6a20d427 100644 --- a/app/controllers/admin/products_controller.rb +++ b/app/controllers/admin/products_controller.rb @@ -1,4 +1,7 @@ class Admin::ProductsController < ApplicationController + before_action :authenticate_user! + before_action :admin_required + def index @products = Product.all end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e1..3bd9979d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,8 @@ 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 + current_user.admin? + end end diff --git a/app/models/user.rb b/app/models/user.rb index c8220270..2a15996a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,4 +3,8 @@ class User < ActiveRecord::Base # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable + + def admin? + is_admin + end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index da9769de..c12ac0c5 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,6 +7,11 @@ <%= csrf_meta_tags %> + <% if !current_user %> + <%= link_to("登入", new_user_session_path) %> + <% else %> + <%= link_to("登出", destroy_user_session_path, :method => :delete ) %> + <% end %> <%= yield %> diff --git a/db/migrate/20140609122603_devise_create_users b/db/migrate/20140609122603_devise_create_users.rb similarity index 100% rename from db/migrate/20140609122603_devise_create_users rename to db/migrate/20140609122603_devise_create_users.rb diff --git a/db/migrate/20140609124047_add_is_admin_to_user.rb b/db/migrate/20140609124047_add_is_admin_to_user.rb new file mode 100644 index 00000000..1ef84cff --- /dev/null +++ b/db/migrate/20140609124047_add_is_admin_to_user.rb @@ -0,0 +1,5 @@ +class AddIsAdminToUser < ActiveRecord::Migration + def change + add_column :users, :is_admin, :boolean, :default => false + end +end diff --git a/db/schema.rb b/db/schema.rb index de172dac..653999c0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140609120041) do +ActiveRecord::Schema.define(version: 20140609124047) do create_table "products", force: true do |t| t.string "title" @@ -21,4 +21,23 @@ t.datetime "updated_at" end + create_table "users", force: true do |t| + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", default: 0, null: false + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "is_admin", default: false + end + + add_index "users", ["email"], name: "index_users_on_email", unique: true + add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + end From 58cd933f95caee7f563ce1dc913ef09aa22e38a3 Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 9 Jun 2014 21:10:30 +0800 Subject: [PATCH 04/59] add bootstrap gem --- Gemfile | 2 ++ Gemfile.lock | 3 +++ app/assets/stylesheets/application.css | 1 + 3 files changed, 6 insertions(+) diff --git a/Gemfile b/Gemfile index 6816d790..e4da45b9 100644 --- a/Gemfile +++ b/Gemfile @@ -39,3 +39,5 @@ gem 'spring', group: :development # gem 'debugger', group: [:development, :test] gem 'devise' + +gem 'bootstrap-sass' diff --git a/Gemfile.lock b/Gemfile.lock index 3c73e9a5..b73e9a14 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -31,6 +31,8 @@ GEM bcrypt (3.1.7) bcrypt-ruby (3.1.5) bcrypt (>= 3.1.3) + bootstrap-sass (3.1.1.1) + sass (~> 3.2) builder (3.2.2) coffee-rails (4.0.1) coffee-script (>= 2.2.0) @@ -125,6 +127,7 @@ PLATFORMS ruby DEPENDENCIES + bootstrap-sass coffee-rails (~> 4.0.0) devise jbuilder (~> 2.0) diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index a443db34..bcdb41c0 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -12,4 +12,5 @@ * *= require_tree . *= require_self + *= require bootstrap */ From ddc98393ef820d665c87398dbab5d2b3fca98656 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 19:51:55 +0800 Subject: [PATCH 05/59] add home page --- app/assets/javascripts/pages.js.coffee | 3 +++ app/assets/stylesheets/pages.css.scss | 3 +++ app/controllers/pages_controller.rb | 4 ++++ app/helpers/pages_helper.rb | 2 ++ app/views/pages/home.html.erb | 4 ++++ config/routes.rb | 1 + test/controllers/pages_controller_test.rb | 7 +++++++ test/helpers/pages_helper_test.rb | 4 ++++ 8 files changed, 28 insertions(+) create mode 100644 app/assets/javascripts/pages.js.coffee create mode 100644 app/assets/stylesheets/pages.css.scss create mode 100644 app/controllers/pages_controller.rb create mode 100644 app/helpers/pages_helper.rb create mode 100644 app/views/pages/home.html.erb create mode 100644 test/controllers/pages_controller_test.rb create mode 100644 test/helpers/pages_helper_test.rb diff --git a/app/assets/javascripts/pages.js.coffee b/app/assets/javascripts/pages.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/pages.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/stylesheets/pages.css.scss b/app/assets/stylesheets/pages.css.scss new file mode 100644 index 00000000..0d6878aa --- /dev/null +++ b/app/assets/stylesheets/pages.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the pages controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb new file mode 100644 index 00000000..45f463e4 --- /dev/null +++ b/app/controllers/pages_controller.rb @@ -0,0 +1,4 @@ +class PagesController < ApplicationController + def home + end +end diff --git a/app/helpers/pages_helper.rb b/app/helpers/pages_helper.rb new file mode 100644 index 00000000..2c057fd0 --- /dev/null +++ b/app/helpers/pages_helper.rb @@ -0,0 +1,2 @@ +module PagesHelper +end diff --git a/app/views/pages/home.html.erb b/app/views/pages/home.html.erb new file mode 100644 index 00000000..9159dd50 --- /dev/null +++ b/app/views/pages/home.html.erb @@ -0,0 +1,4 @@ +

Welcome

+
+

<%= link_to("admin", admin_products_path) %>

+
diff --git a/config/routes.rb b/config/routes.rb index 27c618c3..fc1ee6c6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + root to: "pages#home" devise_for :users namespace :admin do resources :products diff --git a/test/controllers/pages_controller_test.rb b/test/controllers/pages_controller_test.rb new file mode 100644 index 00000000..bb843221 --- /dev/null +++ b/test/controllers/pages_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class PagesControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/helpers/pages_helper_test.rb b/test/helpers/pages_helper_test.rb new file mode 100644 index 00000000..535dfe17 --- /dev/null +++ b/test/helpers/pages_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class PagesHelperTest < ActionView::TestCase +end From 37317224371ee93d656f3b0191e61c3788935159 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 20:29:11 +0800 Subject: [PATCH 06/59] 1. move admin link to application.html 2. add photo of product. --- Gemfile | 5 ++ Gemfile.lock | 6 +++ TODO | 12 +++-- app/models/product.rb | 1 + app/uploaders/photo_uploader.rb | 51 +++++++++++++++++++ app/views/admin/products/new.html.erb | 8 ++- app/views/layouts/application.html.erb | 6 ++- app/views/pages/home.html.erb | 3 -- .../20140611120235_add_photo_to_products.rb | 5 ++ db/schema.rb | 3 +- 10 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 app/uploaders/photo_uploader.rb create mode 100644 db/migrate/20140611120235_add_photo_to_products.rb diff --git a/Gemfile b/Gemfile index e4da45b9..6d86b674 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,11 @@ gem 'spring', group: :development # Use debugger # gem 'debugger', group: [:development, :test] +#for account authentication gem 'devise' +#for front-end gem 'bootstrap-sass' + +#for upload file +gem 'carrierwave' diff --git a/Gemfile.lock b/Gemfile.lock index b73e9a14..108366bd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -34,6 +34,11 @@ GEM bootstrap-sass (3.1.1.1) 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) coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) @@ -128,6 +133,7 @@ PLATFORMS DEPENDENCIES bootstrap-sass + carrierwave coffee-rails (~> 4.0.0) devise jbuilder (~> 2.0) diff --git a/TODO b/TODO index a0d69f7e..c0281066 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,13 @@ ☐ 身為商家的管理者,我要能夠在後台上架我的東西,並設定能夠販賣 - ☐ 管理者必須要有一個後台 - ☐ 後台必須要可以新增產品 - ☐ 產品內容必須要有標題,文字,數量,圖片 + ✔ 管理者必須要有一個後台 @done (14-06-09 21:51) + ✔ 後台必須要可以新增產品 @done (14-06-09 21:51) + ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) + ✔ 產品必須要有圖片 @done(2014-06-11 08:28) + ☐ 身為管理者,可以在後台看到上架產品的內容 + ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 ☐ 身為管理者,才可以進入後台 ☐ 身為管理者,必須要登入且是admin ☐ 管理者身份必須要被分為admin/user - - + ☐ 身為user, 必須不能進入admin namespace. diff --git a/app/models/product.rb b/app/models/product.rb index 077a8197..e04a0475 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -1,2 +1,3 @@ class Product < ActiveRecord::Base + mount_uploader :photo, PhotoUploader end diff --git a/app/uploaders/photo_uploader.rb b/app/uploaders/photo_uploader.rb new file mode 100644 index 00000000..10d845cd --- /dev/null +++ b/app/uploaders/photo_uploader.rb @@ -0,0 +1,51 @@ +# encoding: utf-8 + +class PhotoUploader < 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/products/new.html.erb b/app/views/admin/products/new.html.erb index 625ac4ac..8c383baa 100644 --- a/app/views/admin/products/new.html.erb +++ b/app/views/admin/products/new.html.erb @@ -1,6 +1,6 @@ <%= form_for [:admin, @product] do |f| %>
- <%= f.label("權限") %> + <%= f.label("標題") %> <%= f.text_field :title %>
@@ -10,8 +10,12 @@
- <%= f.label("權限") %> + <%= f.label("數量") %> <%= f.text_field :quantity %>
+
+ <%= f.label("圖片") %> + <%= f.file_field :photo %> +
<%= f.submit "Submit", :disable_with => 'Submiting....' %> <% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index c12ac0c5..9c810d6c 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -11,7 +11,11 @@ <%= link_to("登入", new_user_session_path) %> <% else %> <%= link_to("登出", destroy_user_session_path, :method => :delete ) %> - <% end %> + <% if current_user.admin? %> + <%= link_to("後台", admin_products_path) %> + <% end %> + <% end %> + <%= yield %> diff --git a/app/views/pages/home.html.erb b/app/views/pages/home.html.erb index 9159dd50..dc61c8a5 100644 --- a/app/views/pages/home.html.erb +++ b/app/views/pages/home.html.erb @@ -1,4 +1 @@

Welcome

-
-

<%= link_to("admin", admin_products_path) %>

-
diff --git a/db/migrate/20140611120235_add_photo_to_products.rb b/db/migrate/20140611120235_add_photo_to_products.rb new file mode 100644 index 00000000..bae28f4b --- /dev/null +++ b/db/migrate/20140611120235_add_photo_to_products.rb @@ -0,0 +1,5 @@ +class AddPhotoToProducts < ActiveRecord::Migration + def change + add_column :products, :photo, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 653999c0..c1d9933a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140609124047) do +ActiveRecord::Schema.define(version: 20140611120235) do create_table "products", force: true do |t| t.string "title" @@ -19,6 +19,7 @@ t.integer "quantity" t.datetime "created_at" t.datetime "updated_at" + t.string "photo" end create_table "users", force: true do |t| From 6edc67ad39ce5684d8298226fc6ded92acb8142d Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 21:46:11 +0800 Subject: [PATCH 07/59] add photo model for store multi image in one product --- TODO | 1 + app/controllers/admin/products_controller.rb | 3 ++- app/models/photo.rb | 5 +++++ app/models/product.rb | 3 ++- app/views/admin/products/new.html.erb | 6 ++++-- db/migrate/20140611124013_delete_photo_from_product.rb | 5 +++++ db/migrate/20140611125349_create_photos.rb | 10 ++++++++++ db/schema.rb | 10 ++++++++-- test/fixtures/photos.yml | 9 +++++++++ test/models/photo_test.rb | 7 +++++++ 10 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 app/models/photo.rb create mode 100644 db/migrate/20140611124013_delete_photo_from_product.rb create mode 100644 db/migrate/20140611125349_create_photos.rb create mode 100644 test/fixtures/photos.yml create mode 100644 test/models/photo_test.rb diff --git a/TODO b/TODO index c0281066..f2430e61 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,7 @@ ✔ 後台必須要可以新增產品 @done (14-06-09 21:51) ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) + ☐ 一個產品可以有很多圖片 ☐ 身為管理者,可以在後台看到上架產品的內容 diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb index 6a20d427..8a750e79 100644 --- a/app/controllers/admin/products_controller.rb +++ b/app/controllers/admin/products_controller.rb @@ -8,6 +8,7 @@ def index def new @product = Product.new + @product.photos.build end def create @@ -22,6 +23,6 @@ def create private def product_params - params.require(:product).permit(:title, :description, :quantity) + params.require(:product).permit(:title, :description, :quantity, :photos_attributes => [:image]) end end diff --git a/app/models/photo.rb b/app/models/photo.rb new file mode 100644 index 00000000..513fc4cc --- /dev/null +++ b/app/models/photo.rb @@ -0,0 +1,5 @@ + +class Photo < ActiveRecord::Base + belongs_to :product + mount_uploader :image, PhotoUploader +end diff --git a/app/models/product.rb b/app/models/product.rb index e04a0475..12359d05 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -1,3 +1,4 @@ class Product < ActiveRecord::Base - mount_uploader :photo, PhotoUploader + has_many :photos + accepts_nested_attributes_for :photos end diff --git a/app/views/admin/products/new.html.erb b/app/views/admin/products/new.html.erb index 8c383baa..663a043c 100644 --- a/app/views/admin/products/new.html.erb +++ b/app/views/admin/products/new.html.erb @@ -14,8 +14,10 @@ <%= f.text_field :quantity %>
- <%= f.label("圖片") %> - <%= f.file_field :photo %> + <%= f.fields_for :photos do |photo| %> + <%= photo.label("圖片") %> + <%= photo.file_field :image %> + <% end %>
<%= f.submit "Submit", :disable_with => 'Submiting....' %> <% end %> diff --git a/db/migrate/20140611124013_delete_photo_from_product.rb b/db/migrate/20140611124013_delete_photo_from_product.rb new file mode 100644 index 00000000..4efda5b4 --- /dev/null +++ b/db/migrate/20140611124013_delete_photo_from_product.rb @@ -0,0 +1,5 @@ +class DeletePhotoFromProduct < ActiveRecord::Migration + def change + remove_column :products, :photo, :string + end +end diff --git a/db/migrate/20140611125349_create_photos.rb b/db/migrate/20140611125349_create_photos.rb new file mode 100644 index 00000000..de592bf4 --- /dev/null +++ b/db/migrate/20140611125349_create_photos.rb @@ -0,0 +1,10 @@ +class CreatePhotos < ActiveRecord::Migration + def change + create_table :photos do |t| + t.integer :product_id + t.string :image + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c1d9933a..a8a29a22 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,14 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140611120235) do +ActiveRecord::Schema.define(version: 20140611125349) do + + create_table "photos", force: true do |t| + t.integer "product_id" + t.string "image" + t.datetime "created_at" + t.datetime "updated_at" + end create_table "products", force: true do |t| t.string "title" @@ -19,7 +26,6 @@ t.integer "quantity" t.datetime "created_at" t.datetime "updated_at" - t.string "photo" end create_table "users", force: true do |t| diff --git a/test/fixtures/photos.yml b/test/fixtures/photos.yml new file mode 100644 index 00000000..5cc49b72 --- /dev/null +++ b/test/fixtures/photos.yml @@ -0,0 +1,9 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + product_id: 1 + image: MyString + +two: + product_id: 1 + image: MyString diff --git a/test/models/photo_test.rb b/test/models/photo_test.rb new file mode 100644 index 00000000..e2ec03a1 --- /dev/null +++ b/test/models/photo_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class PhotoTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 587824976802d60da9adb59ab708b4a46fa5a016 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 21:59:01 +0800 Subject: [PATCH 08/59] add admin/product show --- TODO | 4 ++-- app/controllers/admin/products_controller.rb | 4 ++++ app/views/admin/products/show.html.erb | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 app/views/admin/products/show.html.erb diff --git a/TODO b/TODO index f2430e61..4498e51f 100644 --- a/TODO +++ b/TODO @@ -3,8 +3,8 @@ ✔ 後台必須要可以新增產品 @done (14-06-09 21:51) ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) - ☐ 一個產品可以有很多圖片 - ☐ 身為管理者,可以在後台看到上架產品的內容 + ✔ 一個產品可以有很多圖片 @done(2014-06-11 09:58) + ✔ 身為管理者,可以在後台看到上架產品的內容 @done(2014-06-11 09:58) ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb index 8a750e79..a0a1dc26 100644 --- a/app/controllers/admin/products_controller.rb +++ b/app/controllers/admin/products_controller.rb @@ -11,6 +11,10 @@ def new @product.photos.build end + def show + @product = Product.find(params[:id]) + end + def create @product = Product.new(product_params) diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb new file mode 100644 index 00000000..dbc312d5 --- /dev/null +++ b/app/views/admin/products/show.html.erb @@ -0,0 +1,7 @@ +
+

標題:<%= @product.title %>

+

描述:<%= @product.description %>

+

數量:<%= @product.quantity %>

+

圖片:

+ <%= image_tag @product.photos.first.image.url %> +
From 1e6750adf2a064665c4c6197d1e914ce5862dc0d Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 22:12:53 +0800 Subject: [PATCH 09/59] using simple_form --- Gemfile | 2 + Gemfile.lock | 2 + TODO | 9 ++- app/views/admin/products/new.html.erb | 16 ++-- config/initializers/simple_form.rb | 93 +++++++++++++++++++++++ config/locales/simple_form.en.yml | 24 ++++++ lib/templates/erb/scaffold/_form.html.erb | 13 ++++ 7 files changed, 145 insertions(+), 14 deletions(-) create mode 100644 config/initializers/simple_form.rb create mode 100644 config/locales/simple_form.en.yml create mode 100644 lib/templates/erb/scaffold/_form.html.erb diff --git a/Gemfile b/Gemfile index 6d86b674..a7003b04 100644 --- a/Gemfile +++ b/Gemfile @@ -46,3 +46,5 @@ gem 'bootstrap-sass' #for upload file gem 'carrierwave' + +gem 'simple_form' diff --git a/Gemfile.lock b/Gemfile.lock index 108366bd..6fa701da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -101,6 +101,7 @@ GEM sdoc (0.4.0) json (~> 1.8) rdoc (~> 4.0, < 5.0) + simple_form (1.4.1) spring (1.1.3) sprockets (2.11.0) hike (~> 1.2) @@ -141,6 +142,7 @@ DEPENDENCIES rails (= 4.1.0) sass-rails (~> 4.0.3) sdoc (~> 0.4.0) + simple_form spring sqlite3 turbolinks diff --git a/TODO b/TODO index 4498e51f..a648100a 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,15 @@ ☐ 身為商家的管理者,我要能夠在後台上架我的東西,並設定能夠販賣 ✔ 管理者必須要有一個後台 @done (14-06-09 21:51) ✔ 後台必須要可以新增產品 @done (14-06-09 21:51) + ✔ 新增產品使用simple_form @done(2014-06-11 10:11) ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) - ✔ 一個產品可以有很多圖片 @done(2014-06-11 09:58) + ☐ 一個產品可以有很多圖片 + ☐ 限制圖片解析度 ✔ 身為管理者,可以在後台看到上架產品的內容 @done(2014-06-11 09:58) ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 ☐ 身為管理者,才可以進入後台 - ☐ 身為管理者,必須要登入且是admin - ☐ 管理者身份必須要被分為admin/user - ☐ 身為user, 必須不能進入admin namespace. + ✔ 身為管理者,必須要登入且是admin @done(2014-06-11 10:00) + ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) diff --git a/app/views/admin/products/new.html.erb b/app/views/admin/products/new.html.erb index 663a043c..2f934da0 100644 --- a/app/views/admin/products/new.html.erb +++ b/app/views/admin/products/new.html.erb @@ -1,23 +1,19 @@ -<%= form_for [:admin, @product] do |f| %> +<%= simple_form_for [:admin, @product] do |f| %>
- <%= f.label("標題") %> - <%= f.text_field :title %> + <%= f.input :title, label: "標題" %>
- <%= f.label("敘述") %> - <%= f.text_area :description %> + <%= f.input :description, label: "敘述" %>
- <%= f.label("數量") %> - <%= f.text_field :quantity %> + <%= f.input :quantity, label: "數量" %>
<%= f.fields_for :photos do |photo| %> - <%= photo.label("圖片") %> - <%= photo.file_field :image %> + <%= photo.input :image, label: "圖片", as: :file %> <% end %>
- <%= f.submit "Submit", :disable_with => 'Submiting....' %> + <%= f.button :submit, :disable_with => 'Submiting....' %> <% end %> diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb new file mode 100644 index 00000000..553961ba --- /dev/null +++ b/config/initializers/simple_form.rb @@ -0,0 +1,93 @@ +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| + # Components used by the form builder to generate a complete input. You can remove + # any of them, change the order, or even add your own components to the stack. + # config.components = [ :placeholder, :label_input, :hint, :error ] + + # Default tag used on hints. + # config.hint_tag = :span + + # CSS class to add to all hint tags. + # config.hint_class = :hint + + # CSS class used on errors. + # config.error_class = :error + + # Default tag used on errors. + # config.error_tag = :span + + # Method used to tidy up errors. + # config.error_method = :first + + # Default tag used for error notification helper. + # config.error_notification_tag = :p + + # CSS class to add for error notification helper. + # config.error_notification_class = :error_notification + + # ID to add for error notification helper. + # config.error_notification_id = nil + + # You can wrap all inputs in a pre-defined tag. + # config.wrapper_tag = :div + + # CSS class to add to all wrapper tags. + # config.wrapper_class = :input + + # CSS class to add to the wrapper if the field has errors. + # config.wrapper_error_class = :field_with_errors + + # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. + # config.collection_wrapper_tag = nil + + # You can wrap each item in a collection of radio/check boxes with a tag, defaulting to span. + # config.item_wrapper_tag = :span + + # Series of attempts to detect a default label method for collection. + # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] + + # Series of attempts to detect a default value method for collection. + # config.collection_value_methods = [ :id, :to_s ] + + # How the label text should be generated altogether with the required text. + # config.label_text = lambda { |label, required| "#{required} #{label}" } + + # You can define the class to use on all labels. Default is nil. + # config.label_class = nil + + # You can define the class to use on all forms. Default is simple_form. + # config.form_class = :simple_form + + # Whether attributes are required by default (or not). Default is true. + # config.required_by_default = true + + # Tell browsers whether to use default HTML5 validations (novalidate option). + # Default is enabled. + # config.browser_validations = true + + # Determines whether HTML5 types (:email, :url, :search, :tel) and attributes + # (e.g. required) are used or not. True by default. + # Having this on in non-HTML5 compliant sites can cause odd behavior in + # HTML5-aware browsers such as Chrome. + # config.html5 = true + + # Custom mappings for input types. This should be a hash containing a regexp + # to match as key, and the input type that will be used when the field name + # matches the regexp as value. + # config.input_mappings = { /count/ => :integer } + + # Collection of methods to detect if a file type was given. + # config.file_methods = [ :mounted_as, :file?, :public_filename ] + + # Default priority for time_zone inputs. + # config.time_zone_priority = nil + + # Default priority for country inputs. + # config.country_priority = nil + + # Default size for text inputs. + # config.default_input_size = 50 + + # When false, do not use translations for labels, hints or placeholders. + # config.translate = true +end diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml new file mode 100644 index 00000000..409e2651 --- /dev/null +++ b/config/locales/simple_form.en.yml @@ -0,0 +1,24 @@ +en: + simple_form: + "yes": 'Yes' + "no": 'No' + required: + text: 'required' + mark: '*' + # You can uncomment the line below if you need to overwrite the whole required html. + # When using html, text and mark won't be used. + # html: '*' + error_notification: + default_message: "Some errors were found, please take a look:" + # Labels and hints examples + # labels: + # password: 'Password' + # user: + # new: + # email: 'E-mail para efetuar o sign in.' + # edit: + # email: 'E-mail.' + # hints: + # username: 'User name to sign in.' + # password: 'No special characters, please.' + diff --git a/lib/templates/erb/scaffold/_form.html.erb b/lib/templates/erb/scaffold/_form.html.erb new file mode 100644 index 00000000..24a17689 --- /dev/null +++ b/lib/templates/erb/scaffold/_form.html.erb @@ -0,0 +1,13 @@ +<%%= simple_form_for(@<%= singular_table_name %>) do |f| %> + <%%= f.error_notification %> + +
+ <%- attributes.each do |attribute| -%> + <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> + <%- end -%> +
+ +
+ <%%= f.button :submit %> +
+<%% end %> From b4a6e1544056c16c6dd1afe3e7de38958bfb1f12 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 22:19:12 +0800 Subject: [PATCH 10/59] add new link in index page of products --- TODO | 3 +++ app/views/admin/products/index.html.erb | 13 ++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/TODO b/TODO index a648100a..2a805de6 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,9 @@ ☐ 一個產品可以有很多圖片 ☐ 限制圖片解析度 ✔ 身為管理者,可以在後台看到上架產品的內容 @done(2014-06-11 09:58) + ✔ 管理者可以在後台看到所有產品 @done(2014-06-11 10:17) + ✔ 管理者可以在所有產品頁面進入新增產品頁面 @done(2014-06-11 10:17) + ☐ 管理者希望看到美觀的後台管理界面, 使用bootstrap ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 diff --git a/app/views/admin/products/index.html.erb b/app/views/admin/products/index.html.erb index 8a709b89..95d3debc 100644 --- a/app/views/admin/products/index.html.erb +++ b/app/views/admin/products/index.html.erb @@ -1,5 +1,8 @@ -
    - <% @products.each do |product| %> -
  • <%= link_to(product.title, admin_product_path(product)) %>
  • - <% end %> -
+
+ <%= link_to("新增", new_admin_product_path) %> +
    + <% @products.each do |product| %> +
  • <%= link_to(product.title, admin_product_path(product)) %>
  • + <% end %> +
+
From b68dcc045b66abfca98dc22fc5bc995d03845659 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 22:40:11 +0800 Subject: [PATCH 11/59] add nav bar --- app/assets/javascripts/application.js | 1 + app/views/layouts/application.html.erb | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index d6925fa4..77431764 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -14,3 +14,4 @@ //= require jquery_ujs //= require turbolinks //= require_tree . +//= require bootstrap diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9c810d6c..caa432f7 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,14 +7,23 @@ <%= csrf_meta_tags %> - <% if !current_user %> - <%= link_to("登入", new_user_session_path) %> - <% else %> - <%= link_to("登出", destroy_user_session_path, :method => :delete ) %> - <% if current_user.admin? %> - <%= link_to("後台", admin_products_path) %> - <% end %> - <% end %> + <%= yield %> From 9bd414d82cc3a570f2b35b4eb3c27942d4f47a6f Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 11 Jun 2014 23:47:52 +0800 Subject: [PATCH 12/59] custom devise sign in layout with bootstrap and simple_form --- app/views/devise/confirmations/new.html.erb | 16 +++++++++++ .../mailer/confirmation_instructions.html.erb | 5 ++++ .../reset_password_instructions.html.erb | 8 ++++++ .../mailer/unlock_instructions.html.erb | 7 +++++ app/views/devise/passwords/edit.html.erb | 19 +++++++++++++ app/views/devise/passwords/new.html.erb | 15 +++++++++++ app/views/devise/registrations/edit.html.erb | 27 +++++++++++++++++++ app/views/devise/registrations/new.html.erb | 17 ++++++++++++ app/views/devise/sessions/new.html.erb | 16 +++++++++++ app/views/devise/shared/_links.erb | 25 +++++++++++++++++ app/views/devise/unlocks/new.html.erb | 16 +++++++++++ 11 files changed, 171 insertions(+) create mode 100644 app/views/devise/confirmations/new.html.erb create mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 app/views/devise/mailer/unlock_instructions.html.erb create mode 100644 app/views/devise/passwords/edit.html.erb create mode 100644 app/views/devise/passwords/new.html.erb create mode 100644 app/views/devise/registrations/edit.html.erb create mode 100644 app/views/devise/registrations/new.html.erb create mode 100644 app/views/devise/sessions/new.html.erb create mode 100644 app/views/devise/shared/_links.erb create mode 100644 app/views/devise/unlocks/new.html.erb diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 00000000..c80829ad --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,16 @@ +

Resend confirmation instructions

+ +<%= simple_form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %> + <%= f.error_notification %> + <%= f.full_error :confirmation_token %> + +
+ <%= f.input :email, :required => true, :autofocus => true %> +
+ +
+ <%= f.button :submit, "Resend confirmation instructions" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 00000000..36670f91 --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

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 00000000..93de6d05 --- /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 00000000..f59615fe --- /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 00000000..5a2442a6 --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,19 @@ +

Change your password

+ +<%= simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> + <%= f.error_notification %> + + <%= f.input :reset_password_token, :as => :hidden %> + <%= f.full_error :reset_password_token %> + +
+ <%= f.input :password, :label => "New password", :required => true, :autofocus => true %> + <%= f.input :password_confirmation, :label => "Confirm your new password", :required => true %> +
+ +
+ <%= f.button :submit, "Change my password" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 00000000..b196bc90 --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,15 @@ +

Forgot your password?

+ +<%= simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %> + <%= f.error_notification %> + +
+ <%= f.input :email, :required => true, :autofocus => true %> +
+ +
+ <%= f.button :submit, "Send me reset password instructions" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb new file mode 100644 index 00000000..6955c2c7 --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,27 @@ +

Edit <%= resource_name.to_s.humanize %>

+ +<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + <%= f.error_notification %> + +
+ <%= f.input :email, :required => true, :autofocus => true %> + + <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> +

Currently waiting confirmation for: <%= resource.unconfirmed_email %>

+ <% end %> + + <%= f.input :password, :autocomplete => "off", :hint => "leave it blank if you don't want to change it", :required => false %> + <%= f.input :password_confirmation, :required => false %> + <%= f.input :current_password, :hint => "we need your current password to confirm your changes", :required => true %> +
+ +
+ <%= f.button :submit, "Update" %> +
+<% end %> + +

Cancel my account

+ +

Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %>

+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 00000000..c347084c --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,17 @@ +

Sign up

+ +<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name) do |f| %> + <%= f.error_notification %> + +
+ <%= f.input :email, :required => true, :autofocus => true %> + <%= f.input :password, :required => true %> + <%= f.input :password_confirmation, :required => true %> +
+ +
+ <%= f.button :submit, "Sign up" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 00000000..527ee5d4 --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,16 @@ +
+ <%= simple_form_for(resource, :as => resource_name, html: { class: 'form-signin', role: 'form' }, :url => session_path(resource_name)) do |f| %> + +
+ <%= f.input :email, :placeholder => "Email", :label => false, :required => true, :autofocus => true, :input_html => {:class => "form-control"} %> + <%= f.input :password, :placeholder => "Password", :label => false, :required => true, :input_html => {:class => "form-control"} %> + <%= f.input :remember_me, :as => :boolean if devise_mapping.rememberable? %> +
+ +
+ <%= f.button :submit, "Sign in", class: "btn btn-lg btn-primary btn-block" %> +
+ <% end %> + + <%= render "devise/shared/links" %> +
diff --git a/app/views/devise/shared/_links.erb b/app/views/devise/shared/_links.erb new file mode 100644 index 00000000..d84bdde9 --- /dev/null +++ b/app/views/devise/shared/_links.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Sign in", new_session_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
+ <% end -%> +<% end -%> diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 00000000..66495d6a --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,16 @@ +

Resend unlock instructions

+ +<%= simple_form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %> + <%= f.error_notification %> + <%= f.full_error :unlock_token %> + +
+ <%= f.input :email, :required => true, :autofocus => true %> +
+ +
+ <%= f.button :submit, "Resend unlock instructions" %> +
+<% end %> + +<%= render "devise/shared/links" %> From f5846e1dd18adb32a2e3705477c3a2c18b97ee48 Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 12 Jun 2014 21:57:26 +0800 Subject: [PATCH 13/59] admin/product: fix show page error, if product without photo --- app/helpers/admin/products_helper.rb | 7 +++++++ app/views/admin/products/show.html.erb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index 977a242f..0b831239 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,2 +1,9 @@ module Admin::ProductsHelper + def products_render_image + if @product.photos.first != nil + image_tag @product.photos.first.image.url + else + "No Pic" + end + end end diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index dbc312d5..2b2e04c8 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -3,5 +3,5 @@

描述:<%= @product.description %>

數量:<%= @product.quantity %>

圖片:

- <%= image_tag @product.photos.first.image.url %> + <%= products_render_image %> From b6a2d200b1e9776f19fd73433ae6eda1d70a5aee Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 12 Jun 2014 22:07:00 +0800 Subject: [PATCH 14/59] add sign-in style which from example of bootstrap into application.css --- app/assets/stylesheets/application.css | 35 ++++++++++++++++++++++++++ app/views/devise/sessions/new.html.erb | 4 +-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index bcdb41c0..18ec2450 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -14,3 +14,38 @@ *= require_self *= require bootstrap */ + +.form-signin { + max-width: 330px; + padding: 15px; + margin: 0 auto; +} +.form-signin .form-signin-heading, +.form-signin .checkbox { + margin-bottom: 10px; +} +.form-signin .checkbox { + font-weight: normal; +} +.form-signin .form-control { + position: relative; + height: auto; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 10px; + font-size: 16px; +} +.form-signin .form-control:focus { + z-index: 2; +} +.form-signin input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.form-signin input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 527ee5d4..b5a37ad8 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -10,7 +10,7 @@
<%= f.button :submit, "Sign in", class: "btn btn-lg btn-primary btn-block" %>
- <% end %> - <%= render "devise/shared/links" %> + <%= render "devise/shared/links" %> + <% end %> From 182b3ec7f75b14b9ea69fb03079c8ed383ba7923 Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 12 Jun 2014 23:20:04 +0800 Subject: [PATCH 15/59] adm/product: modify layout of show page --- .../stylesheets/admin/products.css.scss | 3 +++ app/helpers/admin/products_helper.rb | 2 +- app/views/admin/products/show.html.erb | 22 ++++++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss index da8969d1..978c2716 100644 --- a/app/assets/stylesheets/admin/products.css.scss +++ b/app/assets/stylesheets/admin/products.css.scss @@ -1,3 +1,6 @@ // 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/ +img{ + max-width: 100%; +} diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index 0b831239..a828bd6a 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,7 +1,7 @@ module Admin::ProductsHelper def products_render_image if @product.photos.first != nil - image_tag @product.photos.first.image.url + image_tag @product.photos.first.image.url, :class => "img-rounded" else "No Pic" end diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index 2b2e04c8..0cb10da6 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -1,7 +1,17 @@ -
-

標題:<%= @product.title %>

-

描述:<%= @product.description %>

-

數量:<%= @product.quantity %>

-

圖片:

- <%= products_render_image %> +
+
+
+

<%= @product.title %>

+
+
+
+
+ <%= products_render_image %> +
+
+

<%= @product.title %>

+

<%= @product.description %>

+

數量:<%= @product.quantity %>

+
+
From ef2b426dc41abd2de99e8af34ff6cfdb2b9305de Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 12 Jun 2014 23:29:55 +0800 Subject: [PATCH 16/59] adm/product: modify layout of new page --- app/views/admin/products/new.html.erb | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/app/views/admin/products/new.html.erb b/app/views/admin/products/new.html.erb index 2f934da0..5c8b84c3 100644 --- a/app/views/admin/products/new.html.erb +++ b/app/views/admin/products/new.html.erb @@ -1,19 +1,23 @@ -<%= simple_form_for [:admin, @product] do |f| %> -
- <%= f.input :title, label: "標題" %> -
+
+ <%= simple_form_for [:admin, @product], html: { role: 'form' } do |f| %> +
+ <%= f.input :title, label: "標題", :input_html => {:class => "form-control"} %> +
-
- <%= f.input :description, label: "敘述" %> -
+
+ <%= f.input :description, label: "敘述", :input_html => {:class => "form-control"} %> +
-
- <%= f.input :quantity, label: "數量" %> -
-
- <%= f.fields_for :photos do |photo| %> - <%= photo.input :image, label: "圖片", as: :file %> - <% end %> -
- <%= f.button :submit, :disable_with => 'Submiting....' %> -<% end %> +
+ <%= f.input :quantity, label: "數量", :input_html => {:class => "form-control"} %> +
+
+ <%= f.fields_for :photos do |photo| %> + <%= photo.input :image, label: "圖片", as: :file, :input_html => {:class => "form-control"} %> + <% end %> +
+
+ <%= f.button :submit, :disable_with => 'Submiting....', class: "btn btn-primary" %> +
+ <% end %> +
From e5e4d363f0bc81ddada0ef4338a84b291238f2dc Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 12 Jun 2014 23:45:00 +0800 Subject: [PATCH 17/59] adm/product: modify layout of index page and update TODO --- TODO | 6 ++++-- app/views/admin/products/index.html.erb | 25 ++++++++++++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/TODO b/TODO index 2a805de6..a52a940c 100644 --- a/TODO +++ b/TODO @@ -5,11 +5,13 @@ ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) ☐ 一個產品可以有很多圖片 - ☐ 限制圖片解析度 + ✔ 限制圖片大小 @done(2014-06-12 11:43) ✔ 身為管理者,可以在後台看到上架產品的內容 @done(2014-06-11 09:58) ✔ 管理者可以在後台看到所有產品 @done(2014-06-11 10:17) ✔ 管理者可以在所有產品頁面進入新增產品頁面 @done(2014-06-11 10:17) - ☐ 管理者希望看到美觀的後台管理界面, 使用bootstrap + ✔ 管理者希望看到美觀的後台管理界面, 使用bootstrap @done(2014-06-12 11:43) + ☐ 管理者希望可以在後台修改產品 + ☐ 管理者希望可以在後台刪除產品 ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 diff --git a/app/views/admin/products/index.html.erb b/app/views/admin/products/index.html.erb index 95d3debc..cfacfc0e 100644 --- a/app/views/admin/products/index.html.erb +++ b/app/views/admin/products/index.html.erb @@ -1,8 +1,19 @@ -
- <%= link_to("新增", new_admin_product_path) %> -
    - <% @products.each do |product| %> -
  • <%= link_to(product.title, admin_product_path(product)) %>
  • - <% end %> -
+
+ <%= link_to("新增", new_admin_product_path, :class => "btn btn-primary") %> + + + + + + + + + <% @products.each do |product| %> + + + + + <% end %> + +
產品連結
<%= product.title %> <%= link_to('Show', admin_product_path(product), :class => "btn btn-info") %>
From c8b3c55f35ee4322f9af490305b3e0e94e6dda39 Mon Sep 17 00:00:00 2001 From: orga Date: Sat, 14 Jun 2014 01:28:15 +0800 Subject: [PATCH 18/59] admin/products: add edit, destroy and update actions --- .gitignore | 3 +++ app/controllers/admin/products_controller.rb | 25 ++++++++++++++++++-- app/helpers/admin/products_helper.rb | 7 ------ app/views/admin/products/edit.html.erb | 19 +++++++++++++++ app/views/admin/products/index.html.erb | 5 +++- app/views/admin/products/show.html.erb | 5 +++- 6 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 app/views/admin/products/edit.html.erb diff --git a/.gitignore b/.gitignore index 6a502e99..389fd328 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ # Ignore all logfiles and tempfiles. /log/*.log /tmp + +# Ignore image files +/public/uploads diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb index a0a1dc26..5295a108 100644 --- a/app/controllers/admin/products_controller.rb +++ b/app/controllers/admin/products_controller.rb @@ -1,6 +1,7 @@ class Admin::ProductsController < ApplicationController before_action :authenticate_user! before_action :admin_required + before_action :find_product, only: [:show, :edit, :update, :destroy] def index @products = Product.all @@ -12,9 +13,8 @@ def new end def show - @product = Product.find(params[:id]) end - + def create @product = Product.new(product_params) @@ -25,7 +25,28 @@ def create end end + def edit + + end + + def update + if @product.update(product_params) + redirect_to admin_product_path(@product) + else + render :edit + end + end + + def destroy + @product.destroy + redirect_to admin_products_path + end + private + def find_product + @product = Product.find(params[:id]) + end + def product_params params.require(:product).permit(:title, :description, :quantity, :photos_attributes => [:image]) end diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index a828bd6a..977a242f 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,9 +1,2 @@ module Admin::ProductsHelper - def products_render_image - if @product.photos.first != nil - image_tag @product.photos.first.image.url, :class => "img-rounded" - else - "No Pic" - end - end end diff --git a/app/views/admin/products/edit.html.erb b/app/views/admin/products/edit.html.erb new file mode 100644 index 00000000..405ff660 --- /dev/null +++ b/app/views/admin/products/edit.html.erb @@ -0,0 +1,19 @@ +
+ <%= simple_form_for [:admin, @product], html: { role: 'form' } do |f| %> +
+ <%= f.input :title, label: "標題", :input_html => {:class => "form-control"} %> +
+ +
+ <%= f.input :description, label: "敘述", :input_html => {:class => "form-control"} %> +
+ +
+ <%= f.input :quantity, label: "數量", :input_html => {:class => "form-control"} %> +
+ +
+ <%= f.button :submit, :disable_with => 'Submiting....', class: "btn btn-primary" %> +
+ <% end %> +
diff --git a/app/views/admin/products/index.html.erb b/app/views/admin/products/index.html.erb index cfacfc0e..25ce5c72 100644 --- a/app/views/admin/products/index.html.erb +++ b/app/views/admin/products/index.html.erb @@ -11,7 +11,10 @@ <% @products.each do |product| %> <%= product.title %> - <%= link_to('Show', admin_product_path(product), :class => "btn btn-info") %> + + <%= link_to('Show', admin_product_path(product), :class => "btn btn-info") %> + <%= link_to('Delete', admin_product_path(product), :method => :delete, :data=>{:confirm=>"Are you sure?"}, :class => "btn btn-warning") %> + <% end %> diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index 0cb10da6..e2c6bd94 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -1,4 +1,5 @@
+ <%= link_to("編輯", edit_admin_product_path(@product), :class => "btn btn-primary") %>

<%= @product.title %>

@@ -6,7 +7,9 @@
- <%= products_render_image %> + <% @product.photos.each do |photo| %> + <%= image_tag photo.image.url, :class => "img-rounded" %> + <% end %>

<%= @product.title %>

From 0aa27db10adbe9c495c08bfc9b82c527eaac6f68 Mon Sep 17 00:00:00 2001 From: orga Date: Sat, 14 Jun 2014 01:51:51 +0800 Subject: [PATCH 19/59] admin/product: add price --- TODO | 1 + app/views/admin/products/edit.html.erb | 6 +++++- app/views/admin/products/new.html.erb | 3 +++ app/views/admin/products/show.html.erb | 1 + db/migrate/20140613173818_add_price_to_product.rb | 5 +++++ db/schema.rb | 3 ++- 6 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20140613173818_add_price_to_product.rb diff --git a/TODO b/TODO index a52a940c..f5645ffd 100644 --- a/TODO +++ b/TODO @@ -5,6 +5,7 @@ ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) ☐ 一個產品可以有很多圖片 + ✔ 產品必須要有價格 @done(2014-06-14 01:51) ✔ 限制圖片大小 @done(2014-06-12 11:43) ✔ 身為管理者,可以在後台看到上架產品的內容 @done(2014-06-11 09:58) ✔ 管理者可以在後台看到所有產品 @done(2014-06-11 10:17) diff --git a/app/views/admin/products/edit.html.erb b/app/views/admin/products/edit.html.erb index 405ff660..a4d7af31 100644 --- a/app/views/admin/products/edit.html.erb +++ b/app/views/admin/products/edit.html.erb @@ -11,7 +11,11 @@
<%= f.input :quantity, label: "數量", :input_html => {:class => "form-control"} %>
- + +
+ <%= f.input :price, label: "價格", :input_html => {:class => "form-control"} %> +
+
<%= f.button :submit, :disable_with => 'Submiting....', class: "btn btn-primary" %>
diff --git a/app/views/admin/products/new.html.erb b/app/views/admin/products/new.html.erb index 5c8b84c3..2ada284a 100644 --- a/app/views/admin/products/new.html.erb +++ b/app/views/admin/products/new.html.erb @@ -11,6 +11,9 @@
<%= f.input :quantity, label: "數量", :input_html => {:class => "form-control"} %>
+
+ <%= f.input :price, label: "價格", :input_html => {:class => "form-control"} %> +
<%= f.fields_for :photos do |photo| %> <%= photo.input :image, label: "圖片", as: :file, :input_html => {:class => "form-control"} %> diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index e2c6bd94..2929ff6d 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -15,6 +15,7 @@

<%= @product.title %>

<%= @product.description %>

數量:<%= @product.quantity %>

+

價格:<%= @product.price %>

diff --git a/db/migrate/20140613173818_add_price_to_product.rb b/db/migrate/20140613173818_add_price_to_product.rb new file mode 100644 index 00000000..af2edf14 --- /dev/null +++ b/db/migrate/20140613173818_add_price_to_product.rb @@ -0,0 +1,5 @@ +class AddPriceToProduct < ActiveRecord::Migration + def change + add_column :products, :price, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index a8a29a22..d0085548 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140611125349) do +ActiveRecord::Schema.define(version: 20140613173818) do create_table "photos", force: true do |t| t.integer "product_id" @@ -26,6 +26,7 @@ t.integer "quantity" t.datetime "created_at" t.datetime "updated_at" + t.integer "price" end create_table "users", force: true do |t| From 0686bfb6560d3c50780bf8ca2997045edd15654a Mon Sep 17 00:00:00 2001 From: orga Date: Sat, 14 Jun 2014 10:00:09 +0800 Subject: [PATCH 20/59] product add validate attributes --- TODO | 1 + app/models/product.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/TODO b/TODO index f5645ffd..f4f4e380 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,7 @@ ☐ 身為商家的管理者,我要能夠在後台上架我的東西,並設定能夠販賣 ✔ 管理者必須要有一個後台 @done (14-06-09 21:51) ✔ 後台必須要可以新增產品 @done (14-06-09 21:51) + ✔ 新增產品必須要有標題, 數量, 價格的內容 @done(2014-06-14 09:59) ✔ 新增產品使用simple_form @done(2014-06-11 10:11) ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) diff --git a/app/models/product.rb b/app/models/product.rb index 12359d05..cd8a16d2 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -1,4 +1,8 @@ class Product < ActiveRecord::Base has_many :photos accepts_nested_attributes_for :photos + + validates :title, :presence => true + validates :quantity, :presence => true + validates :price, :presence => true end From e2e5cabcabc2bbce76319afccce49af6aeeea88a Mon Sep 17 00:00:00 2001 From: orga Date: Sat, 14 Jun 2014 10:34:13 +0800 Subject: [PATCH 21/59] only admin can get into management page --- TODO | 6 +++--- app/controllers/application_controller.rb | 4 +++- app/views/layouts/application.html.erb | 8 ++++++-- app/views/pages/home.html.erb | 4 +++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index f4f4e380..a1a903c8 100644 --- a/TODO +++ b/TODO @@ -12,11 +12,11 @@ ✔ 管理者可以在後台看到所有產品 @done(2014-06-11 10:17) ✔ 管理者可以在所有產品頁面進入新增產品頁面 @done(2014-06-11 10:17) ✔ 管理者希望看到美觀的後台管理界面, 使用bootstrap @done(2014-06-12 11:43) - ☐ 管理者希望可以在後台修改產品 - ☐ 管理者希望可以在後台刪除產品 + ✔ 管理者希望可以在後台修改產品 @done(2014-06-14 10:33) + ✔ 管理者希望可以在後台刪除產品 @done(2014-06-14 10:32) ☐ 身為商家的管理者,我要能夠在後台設定權限,權限分成管理者以及消費者 - ☐ 身為管理者,才可以進入後台 + ✔ 身為管理者,才可以進入後台 @done(2014-06-14 10:33) ✔ 身為管理者,必須要登入且是admin @done(2014-06-11 10:00) ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3bd9979d..ccd18d40 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,8 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception def admin_required - current_user.admin? + unless (current_user && current_user.is_admin?) + redirect_to root_path, :flash => { :error => "no permission" } + end end end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index caa432f7..7e9700e8 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -19,12 +19,16 @@ <% if current_user.admin? %>
  • <%= link_to("後台", admin_products_path) %>
  • <% end %> -
  • <%= link_to("登出", destroy_user_session_path, :method => :delete ) %>
  • +
  • <%= link_to("登出", destroy_user_session_path, :method => :delete ) %>
  • <% end %>
    - + <% if flash[:error] -%> +
    +

    <%= flash[:error] %>

    +
    + <% end %> <%= yield %> diff --git a/app/views/pages/home.html.erb b/app/views/pages/home.html.erb index dc61c8a5..29abd012 100644 --- a/app/views/pages/home.html.erb +++ b/app/views/pages/home.html.erb @@ -1 +1,3 @@ -

    Welcome

    +
    +

    Welcome

    +
    From 31adc6ce963d0edde0cc6d8168982e7d578789fe Mon Sep 17 00:00:00 2001 From: orga Date: Sat, 14 Jun 2014 12:41:42 +0800 Subject: [PATCH 22/59] refactor application.html: extract some layout --- TODO | 5 +++++ app/views/common/_flash_msg.html.erb | 5 +++++ app/views/common/_nav_bar.html.erb | 17 +++++++++++++++++ app/views/layouts/application.html.erb | 24 ++---------------------- 4 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 app/views/common/_flash_msg.html.erb create mode 100644 app/views/common/_nav_bar.html.erb diff --git a/TODO b/TODO index a1a903c8..60b703e7 100644 --- a/TODO +++ b/TODO @@ -20,3 +20,8 @@ ✔ 身為管理者,才可以進入後台 @done(2014-06-14 10:33) ✔ 身為管理者,必須要登入且是admin @done(2014-06-11 10:00) ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) + + +Refactoring: + ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) + ☐ diff --git a/app/views/common/_flash_msg.html.erb b/app/views/common/_flash_msg.html.erb new file mode 100644 index 00000000..ece51242 --- /dev/null +++ b/app/views/common/_flash_msg.html.erb @@ -0,0 +1,5 @@ +<% if flash[:error] %> +
    +

    <%= flash[:error] %>

    +
    +<% end %> diff --git a/app/views/common/_nav_bar.html.erb b/app/views/common/_nav_bar.html.erb new file mode 100644 index 00000000..3d0ca7b2 --- /dev/null +++ b/app/views/common/_nav_bar.html.erb @@ -0,0 +1,17 @@ + diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7e9700e8..12d53781 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,28 +7,8 @@ <%= csrf_meta_tags %> - - <% if flash[:error] -%> -
    -

    <%= flash[:error] %>

    -
    - <% end %> + <%= render "common/nav_bar" %> + <%= render "common/flash_msg" %> <%= yield %> From e1ac0ca1eb176bc96a9796e2dbd10f91dba7f59a Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 11:37:40 +0800 Subject: [PATCH 23/59] Fix price won't be stored: add price attribute into strong parameter --- app/controllers/admin/products_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb index 5295a108..8171bcad 100644 --- a/app/controllers/admin/products_controller.rb +++ b/app/controllers/admin/products_controller.rb @@ -48,6 +48,6 @@ def find_product end def product_params - params.require(:product).permit(:title, :description, :quantity, :photos_attributes => [:image]) + params.require(:product).permit(:title, :description, :quantity, :price, :photos_attributes => [:image]) end end From cdb90202cf1dfea710875c9543f1d3d8f5b3655e Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 11:49:48 +0800 Subject: [PATCH 24/59] alt is necessary attribute of img tag --- app/views/admin/products/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index 2929ff6d..58641354 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -8,7 +8,7 @@
    <% @product.photos.each do |photo| %> - <%= image_tag photo.image.url, :class => "img-rounded" %> + <%= image_tag photo.image.url, :class => "img-rounded", :alt => @product.title %> <% end %>
    From fbdedb23a3393f3e85e7e136d495b3ec774e8e79 Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 12:55:32 +0800 Subject: [PATCH 25/59] move render image into helper and show text of No Pic if the product has not pic uploaded --- TODO | 8 +++++++- app/helpers/admin/products_helper.rb | 7 +++++++ app/models/product.rb | 4 ++++ app/views/admin/products/show.html.erb | 4 +--- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index 60b703e7..338b484c 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +後台管理: ☐ 身為商家的管理者,我要能夠在後台上架我的東西,並設定能夠販賣 ✔ 管理者必須要有一個後台 @done (14-06-09 21:51) ✔ 後台必須要可以新增產品 @done (14-06-09 21:51) @@ -5,6 +6,8 @@ ✔ 新增產品使用simple_form @done(2014-06-11 10:11) ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) + ✔ 如果沒有產品圖片,使用預設文字取代'No Pic' @done(2014-06-15 12:53) @project(後台管理) + ☐ 如果沒有產品圖片,使用預設圖片取代 ☐ 一個產品可以有很多圖片 ✔ 產品必須要有價格 @done(2014-06-14 01:51) ✔ 限制圖片大小 @done(2014-06-12 11:43) @@ -21,7 +24,10 @@ ✔ 身為管理者,必須要登入且是admin @done(2014-06-11 10:00) ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) +系統訊息: + ☐ 身為使用者, 我需要在頁面上看見包含error以外其他種類的通知訊息. -Refactoring: + +重構: ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) ☐ diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index 977a242f..3a1352ad 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,2 +1,9 @@ module Admin::ProductsHelper + def product_render_photo(product) + if product.default_photo.present? + image_tag product.default_photo.image.url, :class => "img-rounded", :alt => product.title + else + "No Pic!" + end + end end diff --git a/app/models/product.rb b/app/models/product.rb index cd8a16d2..afb118c5 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -5,4 +5,8 @@ class Product < ActiveRecord::Base validates :title, :presence => true validates :quantity, :presence => true validates :price, :presence => true + + def default_photo + photos.first + end end diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index 58641354..ca57a6c0 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -7,9 +7,7 @@
    - <% @product.photos.each do |photo| %> - <%= image_tag photo.image.url, :class => "img-rounded", :alt => @product.title %> - <% end %> + <%= product_render_photo(@product) %>

    <%= @product.title %>

    From a5ac8de88504ae6900030b1f1c98bdbfb06fffdf Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 13:09:54 +0800 Subject: [PATCH 26/59] render image: using image instead of raw text of No Pic --- TODO | 2 +- app/helpers/admin/products_helper.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index 338b484c..bfc94c55 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,7 @@ ✔ 產品內容必須要有標題,文字,數量 @done (14-06-09 21:52) ✔ 產品必須要有圖片 @done(2014-06-11 08:28) ✔ 如果沒有產品圖片,使用預設文字取代'No Pic' @done(2014-06-15 12:53) @project(後台管理) - ☐ 如果沒有產品圖片,使用預設圖片取代 + ✔ 如果沒有產品圖片,使用No Pic圖片取代 @done(2014-06-15 01:07) @project(後台管理) ☐ 一個產品可以有很多圖片 ✔ 產品必須要有價格 @done(2014-06-14 01:51) ✔ 限制圖片大小 @done(2014-06-12 11:43) diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index 3a1352ad..8add7ca3 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,9 +1,11 @@ module Admin::ProductsHelper def product_render_photo(product) if product.default_photo.present? - image_tag product.default_photo.image.url, :class => "img-rounded", :alt => product.title + image_url = product.default_photo.image.url else - "No Pic!" + image_url = "http://placehold.it/200x200&text=No Pic" end + + image_tag image_url, :class => "img-rounded", :alt => product.title end end From 7db1d14c30b7e8cfbdee689b7524f31529cf731a Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 14:35:38 +0800 Subject: [PATCH 27/59] resize image when it uploaded and provide a image with different size --- Gemfile | 3 +++ Gemfile.lock | 10 ++++++++++ TODO | 5 ++++- app/helpers/admin/products_helper.rb | 4 ++-- app/uploaders/photo_uploader.rb | 14 +++++++++----- app/views/admin/products/show.html.erb | 2 +- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index a7003b04..ba7fd6b8 100644 --- a/Gemfile +++ b/Gemfile @@ -46,5 +46,8 @@ gem 'bootstrap-sass' #for upload file gem 'carrierwave' +#for process uploaded image +gem 'subexec', :git => "https://github.com/nulayer/subexec.git" +gem 'mini_magick' gem 'simple_form' diff --git a/Gemfile.lock b/Gemfile.lock index 6fa701da..db2ab7d7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,9 @@ +GIT + remote: https://github.com/nulayer/subexec.git + revision: 2e4d92870d4ad3322d6fca14416f63e6eff55cbc + specs: + subexec (0.2.3) + GEM remote: https://rubygems.org/ specs: @@ -67,6 +73,8 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.25.1) + mini_magick (3.7.0) + subexec (~> 0.2.1) minitest (5.3.4) multi_json (1.10.1) orm_adapter (0.5.0) @@ -139,11 +147,13 @@ DEPENDENCIES devise jbuilder (~> 2.0) jquery-rails + mini_magick rails (= 4.1.0) sass-rails (~> 4.0.3) sdoc (~> 0.4.0) simple_form spring sqlite3 + subexec! turbolinks uglifier (>= 1.3.0) diff --git a/TODO b/TODO index bfc94c55..708a5e1a 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,9 @@ ✔ 如果沒有產品圖片,使用No Pic圖片取代 @done(2014-06-15 01:07) @project(後台管理) ☐ 一個產品可以有很多圖片 ✔ 產品必須要有價格 @done(2014-06-14 01:51) - ✔ 限制圖片大小 @done(2014-06-12 11:43) + ✔ 限制圖片顯示大小 @done(2014-06-12 11:43) + ✔ 設定圖片在上傳時的大小並且提供各種大小的版本 @done(2014-06-15 02:33) @project(後台管理) + ☐ 在產品列表顯示產品的小圖片 ✔ 身為管理者,可以在後台看到上架產品的內容 @done(2014-06-11 09:58) ✔ 管理者可以在後台看到所有產品 @done(2014-06-11 10:17) ✔ 管理者可以在所有產品頁面進入新增產品頁面 @done(2014-06-11 10:17) @@ -23,6 +25,7 @@ ✔ 身為管理者,才可以進入後台 @done(2014-06-14 10:33) ✔ 身為管理者,必須要登入且是admin @done(2014-06-11 10:00) ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) + ☐ 身為一般使用者, 需要能看到所有產品 系統訊息: ☐ 身為使用者, 我需要在頁面上看見包含error以外其他種類的通知訊息. diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index 8add7ca3..d4a44396 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,7 +1,7 @@ module Admin::ProductsHelper - def product_render_photo(product) + def product_render_photo(product, size = "thumb") if product.default_photo.present? - image_url = product.default_photo.image.url + image_url = product.default_photo.image.send(size).url else image_url = "http://placehold.it/200x200&text=No Pic" end diff --git a/app/uploaders/photo_uploader.rb b/app/uploaders/photo_uploader.rb index 10d845cd..398bc25a 100644 --- a/app/uploaders/photo_uploader.rb +++ b/app/uploaders/photo_uploader.rb @@ -4,7 +4,7 @@ class PhotoUploader < CarrierWave::Uploader::Base # Include RMagick or MiniMagick support: # include CarrierWave::RMagick - # include CarrierWave::MiniMagick + include CarrierWave::MiniMagick # Choose what kind of storage to use for this uploader: storage :file @@ -25,16 +25,20 @@ def store_dir # end # Process files as they are uploaded: - # process :scale => [200, 300] + process :resize_to_fit => [800, 800] # # def scale(width, height) # # do something # end # Create different versions of your uploaded files: - # version :thumb do - # process :resize_to_fit => [50, 50] - # end + version :thumb do + process :resize_to_fill => [200, 200] + end + + version :medium do + process :resize_to_fill => [400, 400] + end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb index ca57a6c0..924f301a 100644 --- a/app/views/admin/products/show.html.erb +++ b/app/views/admin/products/show.html.erb @@ -7,7 +7,7 @@
    - <%= product_render_photo(@product) %> + <%= product_render_photo(@product, :medium) %>

    <%= @product.title %>

    From a6329a75d6bcb40e9adbc9f5552af8a42cebfbec Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 15:03:51 +0800 Subject: [PATCH 28/59] add product controller and view for normal users access --- TODO | 2 +- app/assets/javascripts/products.js.coffee | 3 + app/assets/stylesheets/products.css.scss | 3 + app/controllers/products_controller.rb | 9 +++ app/helpers/admin/products_helper.rb | 9 --- app/helpers/products_helper.rb | 11 ++++ app/views/products/index.html.erb | 20 +++++++ app/views/products/show.html.erb | 18 ++++++ config/routes.rb | 59 +------------------- test/controllers/products_controller_test.rb | 7 +++ test/helpers/products_helper_test.rb | 4 ++ 11 files changed, 78 insertions(+), 67 deletions(-) create mode 100644 app/assets/javascripts/products.js.coffee create mode 100644 app/assets/stylesheets/products.css.scss create mode 100644 app/controllers/products_controller.rb create mode 100644 app/helpers/products_helper.rb create mode 100644 app/views/products/index.html.erb create mode 100644 app/views/products/show.html.erb create mode 100644 test/controllers/products_controller_test.rb create mode 100644 test/helpers/products_helper_test.rb diff --git a/TODO b/TODO index 708a5e1a..473b9674 100644 --- a/TODO +++ b/TODO @@ -25,7 +25,7 @@ ✔ 身為管理者,才可以進入後台 @done(2014-06-14 10:33) ✔ 身為管理者,必須要登入且是admin @done(2014-06-11 10:00) ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) - ☐ 身為一般使用者, 需要能看到所有產品 + ✔ 身為一般使用者, 需要能看到所有產品 @done(2014-06-15 03:02) 系統訊息: ☐ 身為使用者, 我需要在頁面上看見包含error以外其他種類的通知訊息. diff --git a/app/assets/javascripts/products.js.coffee b/app/assets/javascripts/products.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/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/stylesheets/products.css.scss b/app/assets/stylesheets/products.css.scss new file mode 100644 index 00000000..89e2e8db --- /dev/null +++ b/app/assets/stylesheets/products.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the 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/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 00000000..0e295c25 --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,9 @@ +class ProductsController < ApplicationController + def index + @products = Product.all + end + + def show + @product = Product.find(params[:id]) + end +end diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index d4a44396..977a242f 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -1,11 +1,2 @@ module Admin::ProductsHelper - def product_render_photo(product, size = "thumb") - if product.default_photo.present? - image_url = product.default_photo.image.send(size).url - else - image_url = "http://placehold.it/200x200&text=No Pic" - end - - image_tag image_url, :class => "img-rounded", :alt => product.title - end end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 00000000..3219fb7b --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,11 @@ +module ProductsHelper + def product_render_photo(product, size = "thumb") + if product.default_photo.present? + image_url = product.default_photo.image.send(size).url + else + image_url = "http://placehold.it/200x200&text=No Pic" + end + + image_tag image_url, :class => "img-rounded", :alt => product.title + end +end diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb new file mode 100644 index 00000000..ccd2d149 --- /dev/null +++ b/app/views/products/index.html.erb @@ -0,0 +1,20 @@ +
    + + + + + + + + + <% @products.each do |product| %> + + + + + <% end %> + +
    產品連結
    <%= product.title %> + <%= link_to('Show', product_path(product), :class => "btn btn-info") %> +
    +
    diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb new file mode 100644 index 00000000..f5400cd1 --- /dev/null +++ b/app/views/products/show.html.erb @@ -0,0 +1,18 @@ +
    +
    +
    +

    <%= @product.title %>

    +
    +
    +
    +
    + <%= product_render_photo(@product, :medium) %> +
    +
    +

    <%= @product.title %>

    +

    <%= @product.description %>

    +

    數量:<%= @product.quantity %>

    +

    價格:<%= @product.price %>

    +
    +
    +
    diff --git a/config/routes.rb b/config/routes.rb index fc1ee6c6..5dd2a39d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,64 +1,9 @@ Rails.application.routes.draw do - root to: "pages#home" + root to: "pages#home" devise_for :users namespace :admin do resources :products end - - # The priority is based upon order of creation: first created -> highest priority. - # See how all your routes lay out with "rake routes". - - # You can have the root of your site routed with "root" - # root 'welcome#index' - - # Example of regular route: - # get 'products/:id' => 'catalog#view' - - # Example of named route that can be invoked with purchase_url(id: product.id) - # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase - - # Example resource route (maps HTTP verbs to controller actions automatically): - # resources :products - - # Example resource route with options: - # resources :products do - # member do - # get 'short' - # post 'toggle' - # end - # - # collection do - # get 'sold' - # end - # end - - # Example resource route with sub-resources: - # resources :products do - # resources :comments, :sales - # resource :seller - # end - - # Example resource route with more complex sub-resources: - # resources :products do - # resources :comments - # resources :sales do - # get 'recent', on: :collection - # end - # end - - # Example resource route with concerns: - # concern :toggleable do - # post 'toggle' - # end - # resources :posts, concerns: :toggleable - # resources :photos, concerns: :toggleable - - # Example resource route within a namespace: - # namespace :admin do - # # Directs /admin/products/* to Admin::ProductsController - # # (app/controllers/admin/products_controller.rb) - # resources :products - # end - + resources :products end diff --git a/test/controllers/products_controller_test.rb b/test/controllers/products_controller_test.rb new file mode 100644 index 00000000..c881fa68 --- /dev/null +++ b/test/controllers/products_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ProductsControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/helpers/products_helper_test.rb b/test/helpers/products_helper_test.rb new file mode 100644 index 00000000..0f5beab7 --- /dev/null +++ b/test/helpers/products_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class ProductsHelperTest < ActionView::TestCase +end From 986d0da1b789aec1bc885e09f9a0ac771497be9f Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 15 Jun 2014 15:27:29 +0800 Subject: [PATCH 29/59] add products link to nav bar --- TODO | 3 +++ app/views/common/_nav_bar.html.erb | 1 + 2 files changed, 4 insertions(+) diff --git a/TODO b/TODO index 473b9674..98c28de8 100644 --- a/TODO +++ b/TODO @@ -27,6 +27,9 @@ ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) ✔ 身為一般使用者, 需要能看到所有產品 @done(2014-06-15 03:02) +購物: + ☐ 任何使用者都能在navbar點擊進入商品選單區. + 系統訊息: ☐ 身為使用者, 我需要在頁面上看見包含error以外其他種類的通知訊息. diff --git a/app/views/common/_nav_bar.html.erb b/app/views/common/_nav_bar.html.erb index 3d0ca7b2..1193f1b5 100644 --- a/app/views/common/_nav_bar.html.erb +++ b/app/views/common/_nav_bar.html.erb @@ -4,6 +4,7 @@
    diff --git a/config/routes.rb b/config/routes.rb index 5dd2a39d..9dcb9d43 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,6 +4,22 @@ namespace :admin do resources :products end - resources :products + resources :products do + member do + post :add_to_cart + end + end + + resources :carts do + member do + post :checkout + end + end + + resources :orders do + member do + get :pay_with_credit_card + end + end end diff --git a/db/migrate/20140616111149_create_carts.rb b/db/migrate/20140616111149_create_carts.rb new file mode 100644 index 00000000..8e66adb5 --- /dev/null +++ b/db/migrate/20140616111149_create_carts.rb @@ -0,0 +1,8 @@ +class CreateCarts < ActiveRecord::Migration + def change + create_table :carts do |t| + + t.timestamps + end + end +end diff --git a/db/migrate/20140616111230_create_cart_items.rb b/db/migrate/20140616111230_create_cart_items.rb new file mode 100644 index 00000000..0fb13b18 --- /dev/null +++ b/db/migrate/20140616111230_create_cart_items.rb @@ -0,0 +1,10 @@ +class CreateCartItems < ActiveRecord::Migration + def change + create_table :cart_items do |t| + t.integer :cart_id + t.integer :product_id + + t.timestamps + end + end +end diff --git a/db/migrate/20140616120514_create_orders.rb b/db/migrate/20140616120514_create_orders.rb new file mode 100644 index 00000000..12bf480d --- /dev/null +++ b/db/migrate/20140616120514_create_orders.rb @@ -0,0 +1,10 @@ +class CreateOrders < ActiveRecord::Migration + def change + create_table :orders do |t| + t.integer :user_id + t.integer :total + t.boolean :paid, :default => false + t.timestamps + end + end +end diff --git a/db/migrate/20140616120611_create_order_infos.rb b/db/migrate/20140616120611_create_order_infos.rb new file mode 100644 index 00000000..09d63314 --- /dev/null +++ b/db/migrate/20140616120611_create_order_infos.rb @@ -0,0 +1,13 @@ +class CreateOrderInfos < ActiveRecord::Migration + def change + create_table :order_infos do |t| + t.integer :order_id + t.string :billing_name + t.string :billing_address + + t.string :shipping_name + t.string :shipping_address + t.timestamps + end + end +end diff --git a/db/migrate/20140616120619_create_order_items.rb b/db/migrate/20140616120619_create_order_items.rb new file mode 100644 index 00000000..cebcd4f4 --- /dev/null +++ b/db/migrate/20140616120619_create_order_items.rb @@ -0,0 +1,11 @@ +class CreateOrderItems < ActiveRecord::Migration + def change + create_table :order_items do |t| + t.string :product_name + t.float :price + t.integer :quantity + t.integer :order_id + t.timestamps + end + end +end diff --git a/db/migrate/20140616123020_add_token_to_order.rb b/db/migrate/20140616123020_add_token_to_order.rb new file mode 100644 index 00000000..cb455b41 --- /dev/null +++ b/db/migrate/20140616123020_add_token_to_order.rb @@ -0,0 +1,6 @@ +class AddTokenToOrder < ActiveRecord::Migration + def change + add_column :orders, :token, :string + add_index :orders, :token + end +end diff --git a/db/migrate/20140616124153_add_payment_method_to_order.rb b/db/migrate/20140616124153_add_payment_method_to_order.rb new file mode 100644 index 00000000..e7eb536a --- /dev/null +++ b/db/migrate/20140616124153_add_payment_method_to_order.rb @@ -0,0 +1,5 @@ +class AddPaymentMethodToOrder < ActiveRecord::Migration + def change + add_column :orders, :payment_method, :string + end +end diff --git a/db/migrate/20140616132404_add_aasm_state_to_orders.rb b/db/migrate/20140616132404_add_aasm_state_to_orders.rb new file mode 100644 index 00000000..37097caa --- /dev/null +++ b/db/migrate/20140616132404_add_aasm_state_to_orders.rb @@ -0,0 +1,6 @@ +class AddAasmStateToOrders < ActiveRecord::Migration + def change + add_column :orders, :aasm_state, :string, :default => "order_placed" + add_index :orders, :aasm_state + end +end diff --git a/db/schema.rb b/db/schema.rb index d0085548..08a78c91 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,50 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140613173818) do +ActiveRecord::Schema.define(version: 20140616124153) do + + create_table "cart_items", force: true do |t| + t.integer "cart_id" + t.integer "product_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "carts", force: true do |t| + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "order_infos", force: true do |t| + t.integer "order_id" + t.string "billing_name" + t.string "billing_address" + t.string "shipping_name" + t.string "shipping_address" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "order_items", force: true do |t| + t.string "product_name" + t.float "price" + t.integer "quantity" + t.integer "order_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "orders", force: true do |t| + t.integer "user_id" + t.integer "total" + t.boolean "paid", default: false + t.datetime "created_at" + t.datetime "updated_at" + t.string "token" + t.string "payment_method" + end + + add_index "orders", ["token"], name: "index_orders_on_token" create_table "photos", force: true do |t| t.integer "product_id" diff --git a/test/controllers/carts_controller_test.rb b/test/controllers/carts_controller_test.rb new file mode 100644 index 00000000..1e748b83 --- /dev/null +++ b/test/controllers/carts_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CartsControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/controllers/orders_controller_test.rb b/test/controllers/orders_controller_test.rb new file mode 100644 index 00000000..0afece19 --- /dev/null +++ b/test/controllers/orders_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class OrdersControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/fixtures/cart_items.yml b/test/fixtures/cart_items.yml new file mode 100644 index 00000000..a0de2cb5 --- /dev/null +++ b/test/fixtures/cart_items.yml @@ -0,0 +1,9 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + cart_id: 1 + product_id: 1 + +two: + cart_id: 1 + product_id: 1 diff --git a/test/fixtures/carts.yml b/test/fixtures/carts.yml new file mode 100644 index 00000000..937a0c00 --- /dev/null +++ b/test/fixtures/carts.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/fixtures/order_infos.yml b/test/fixtures/order_infos.yml new file mode 100644 index 00000000..937a0c00 --- /dev/null +++ b/test/fixtures/order_infos.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/fixtures/order_items.yml b/test/fixtures/order_items.yml new file mode 100644 index 00000000..937a0c00 --- /dev/null +++ b/test/fixtures/order_items.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml new file mode 100644 index 00000000..937a0c00 --- /dev/null +++ b/test/fixtures/orders.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/helpers/carts_helper_test.rb b/test/helpers/carts_helper_test.rb new file mode 100644 index 00000000..0fac3c4e --- /dev/null +++ b/test/helpers/carts_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class CartsHelperTest < ActionView::TestCase +end diff --git a/test/helpers/orders_helper_test.rb b/test/helpers/orders_helper_test.rb new file mode 100644 index 00000000..52dacae1 --- /dev/null +++ b/test/helpers/orders_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class OrdersHelperTest < ActionView::TestCase +end diff --git a/test/models/cart_item_test.rb b/test/models/cart_item_test.rb new file mode 100644 index 00000000..881afe1f --- /dev/null +++ b/test/models/cart_item_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CartItemTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/cart_test.rb b/test/models/cart_test.rb new file mode 100644 index 00000000..9fad43a1 --- /dev/null +++ b/test/models/cart_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CartTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/order_info_test.rb b/test/models/order_info_test.rb new file mode 100644 index 00000000..e2689117 --- /dev/null +++ b/test/models/order_info_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class OrderInfoTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/order_items_test.rb b/test/models/order_items_test.rb new file mode 100644 index 00000000..d3b5302c --- /dev/null +++ b/test/models/order_items_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class OrderItemsTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/order_test.rb b/test/models/order_test.rb new file mode 100644 index 00000000..15b8ed13 --- /dev/null +++ b/test/models/order_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class OrderTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From aff7643e8275352b4a3861e3e39dc106cbdd1b91 Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 16 Jun 2014 21:37:05 +0800 Subject: [PATCH 32/59] update schema.rb --- db/schema.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 08a78c91..80246c80 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140616124153) do +ActiveRecord::Schema.define(version: 20140616132404) do create_table "cart_items", force: true do |t| t.integer "cart_id" @@ -52,8 +52,10 @@ t.datetime "updated_at" t.string "token" t.string "payment_method" + t.string "aasm_state", default: "order_placed" end + add_index "orders", ["aasm_state"], name: "index_orders_on_aasm_state" add_index "orders", ["token"], name: "index_orders_on_token" create_table "photos", force: true do |t| From 0e2c20f854251fdf67fc80416d4e7c2941eb015e Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 16 Jun 2014 21:59:25 +0800 Subject: [PATCH 33/59] update TODO --- TODO | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TODO b/TODO index dc881d54..a57ecce2 100644 --- a/TODO +++ b/TODO @@ -29,6 +29,14 @@ 購物: ✔ 任何使用者都能在navbar點擊進入商品選單區. @done(2014-06-15 03:27) @project(購物) + ☐ 作為一個消費者,我要在前台能夠找到商品並結賬 + ✔ 身為消費者,我要在前台能夠找到商品並加到購物⾞ @done(2014-06-16 09:58) @project(購物) + ✔ ⾝為消費者,我要在前台能看到購物⾞明細 @done(2014-06-16 09:58) @project(購物) + ☐ ⾝為消費者,我要在前台能夠將多樣商品加到購物車,並生成一張訂單 + ✔ ⾝為消費者,當系統生成一張訂單前,我可以填寫寄送資訊 @done(2014-06-16 09:58) @project(購物) + ✔ 身為消費者,當系統⽣生成⼀張訂單後,我可以用信用卡結帳 @done(2014-06-16 09:58) @project(購物) + ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 + 系統訊息: ☐ 身為使用者, 我需要在頁面上看見包含error以外其他種類的通知訊息. From 051565308cda6648f296c83a0ee54e64ee939bbc Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 16 Jun 2014 23:49:39 +0800 Subject: [PATCH 34/59] update TODO list for homework v2 --- TODO | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/TODO b/TODO index a57ecce2..6088e5cb 100644 --- a/TODO +++ b/TODO @@ -27,6 +27,12 @@ ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) ✔ 身為一般使用者, 需要能看到所有產品 @done(2014-06-15 03:02) + ☐ 身為商家的管理者,可以在後台看到所有訂單 + ☐ 身為商家的管理者,可以在後台的訂單列表看到每張訂單的狀態 + ☐ 身為商家的管理者,可以在後台每張訂單內按照狀態圖改變狀態 + + + 購物: ✔ 任何使用者都能在navbar點擊進入商品選單區. @done(2014-06-15 03:27) @project(購物) ☐ 作為一個消費者,我要在前台能夠找到商品並結賬 @@ -36,6 +42,17 @@ ✔ ⾝為消費者,當系統生成一張訂單前,我可以填寫寄送資訊 @done(2014-06-16 09:58) @project(購物) ✔ 身為消費者,當系統⽣生成⼀張訂單後,我可以用信用卡結帳 @done(2014-06-16 09:58) @project(購物) ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 + ☐ 信用卡付款成功後也要收到通知信 + ☐ 身為消費者, 可以從信中連結到訂單網頁 + ☐ 身為消費者,當訂單成立後,購物車需要清空 + ☐ 身為消費者,需要在訂單頁面看到正確的商品數量 + ☐ 美化訂單畫面 + ☐ 身為消費者,需要在購物車內刪除商品 + ☐ 身為消費者,可以選擇商品數量,加入購物車 + ☐ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) + ☐ 身為消費者, 不能將數量為0的商品加入購物車 + ☐ 身為消費者, 能在account/orders看到過去的訂單記錄 + ☐ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index 系統訊息: From 9dbcad7939a923956e68149a0b618726054b0f70 Mon Sep 17 00:00:00 2001 From: orga Date: Tue, 17 Jun 2014 22:16:00 +0800 Subject: [PATCH 35/59] user can delete product from cart --- TODO | 2 +- app/controllers/carts_controller.rb | 2 ++ app/controllers/products_controller.rb | 12 ++++++++++++ app/models/cart.rb | 4 ++++ app/views/carts/index.html.erb | 13 ++++++------- config/routes.rb | 1 + 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index 6088e5cb..0820f7de 100644 --- a/TODO +++ b/TODO @@ -47,7 +47,7 @@ ☐ 身為消費者,當訂單成立後,購物車需要清空 ☐ 身為消費者,需要在訂單頁面看到正確的商品數量 ☐ 美化訂單畫面 - ☐ 身為消費者,需要在購物車內刪除商品 + ✔ 身為消費者,需要可以在購物車內刪除商品 @done(2014-06-17 10:11) @project(購物) ☐ 身為消費者,可以選擇商品數量,加入購物車 ☐ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) ☐ 身為消費者, 不能將數量為0的商品加入購物車 diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb index 1ea5c7d0..3a4789f6 100644 --- a/app/controllers/carts_controller.rb +++ b/app/controllers/carts_controller.rb @@ -8,4 +8,6 @@ def checkout @order = current_user.orders.build @info = @order.build_info end + + end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 3c15db93..73ec58fd 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -7,6 +7,18 @@ def show @product = Product.find(params[:id]) end + def del_from_cart + @product = Product.find(params[:id]) + if current_cart.items.include?(@product) + current_cart.del_product_from_cart(@product) + flash[:notice] = "你已成功將 #{@product.title} 移除" + else + flash[:warning] = "你的購物車沒有此物品" + end + + redirect_to carts_path + end + def add_to_cart @product = Product.find(params[:id]) diff --git a/app/models/cart.rb b/app/models/cart.rb index bee815be..1fecf626 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -2,6 +2,10 @@ class Cart < ActiveRecord::Base has_many :cart_items, :dependent => :destroy has_many :items, :through => :cart_items, :source => :product + def del_product_from_cart(product) + items.delete(product) + end + def add_product_to_cart(product) items << product end diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 2b0ff571..ef0380f0 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -10,21 +10,20 @@ 商品資訊 單價 + 動作 <% current_cart.items.each do |product| %> - - <%= product_render_photo(product) %> - + + <%= product_render_photo(product) %> - - - <%= link_to(product.title, product_path(product)) %> + <%= link_to(product.title, product_path(product)) %> <%= product.price %> + <%= link_to("刪除", del_from_cart_product_path(product), :method => :post, :class => "btn btn-primary") %> - <% end %> + <% end %> diff --git a/config/routes.rb b/config/routes.rb index 9dcb9d43..a5306369 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,6 +8,7 @@ resources :products do member do post :add_to_cart + post :del_from_cart end end From 1a5a4b977bf1878a8905230cd923bd1f5dc1a7aa Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 01:07:28 +0800 Subject: [PATCH 36/59] user can choose number of products before add it to cart --- app/controllers/products_controller.rb | 3 ++- app/inputs/fake_input.rb | 6 ++++++ app/views/admin/products/new.html.erb | 2 +- app/views/products/show.html.erb | 13 +++++++++---- 4 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 app/inputs/fake_input.rb diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 73ec58fd..05b61548 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -22,7 +22,8 @@ def del_from_cart def add_to_cart @product = Product.find(params[:id]) - + @item_quantity = params[:item_quantity] + if !current_cart.items.include?(@product) current_cart.add_product_to_cart(@product) flash[:notice] = "你已成功將 #{@product.title} 加入購物車" diff --git a/app/inputs/fake_input.rb b/app/inputs/fake_input.rb new file mode 100644 index 00000000..1ed641e4 --- /dev/null +++ b/app/inputs/fake_input.rb @@ -0,0 +1,6 @@ +class FakeInput < SimpleForm::Inputs::StringInput + # This method only create a basic input without reading any value from object + def input + template.text_field_tag(attribute_name, nil, input_html_options) + end +end diff --git a/app/views/admin/products/new.html.erb b/app/views/admin/products/new.html.erb index 2ada284a..8da69f4d 100644 --- a/app/views/admin/products/new.html.erb +++ b/app/views/admin/products/new.html.erb @@ -1,5 +1,5 @@
    - <%= simple_form_for [:admin, @product], html: { role: 'form' } do |f| %> + <%= simple_form_for [:admin, @product], html: { role: 'form' } do |f| %>
    <%= f.input :title, label: "標題", :input_html => {:class => "form-control"} %>
    diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 58a4809c..21ff951c 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -11,11 +11,16 @@

    <%= @product.title %>

    <%= @product.description %>

    -

    數量:<%= @product.quantity %>

    +

    庫存:<%= @product.quantity %>

    價格:<%= @product.price %>

    -
    - <%= link_to("加入購物車", add_to_cart_product_path(@product) , :method => :post , :class => "btn btn-primary btn-lg btn-danger") %> -
    + <%= simple_form_for @product, url: add_to_cart_product_path(@product), method: :post, html: { role: 'form', class: 'form-inline' } do |f| %> +
    + <%= f.input :item_quantity, label: "數量:", as: :fake, collection: 1..@product.quantity, :input_html => {:class => "form-control"} %> +
    +
    + <%= f.button :submit, :value => "加入購物車", :disable_with => 'Submiting....', class: "btn btn-primary" %> +
    + <% end %>
    From eaa03f579a930294218dfed13b297b9e794adc75 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 01:08:36 +0800 Subject: [PATCH 37/59] user can choose number of products before add it to cart (missing files) --- app/controllers/products_controller.rb | 4 ++-- app/models/cart.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 05b61548..e6c14a6b 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -23,9 +23,9 @@ def add_to_cart @product = Product.find(params[:id]) @item_quantity = params[:item_quantity] - + if !current_cart.items.include?(@product) - current_cart.add_product_to_cart(@product) + current_cart.add_product_to_cart(@product, @item_quantity) flash[:notice] = "你已成功將 #{@product.title} 加入購物車" else flash[:warning] = "你的購物車內已有此物品" diff --git a/app/models/cart.rb b/app/models/cart.rb index 1fecf626..8d049843 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -6,7 +6,7 @@ def del_product_from_cart(product) items.delete(product) end - def add_product_to_cart(product) + def add_product_to_cart(product, item_quantity) items << product end From dd4a2871484a9adf040fc8880c9562c25b743c3c Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 20:34:40 +0800 Subject: [PATCH 38/59] add quantity for each prodcut in cart --- TODO | 2 +- app/controllers/products_controller.rb | 12 ++++++++++-- app/models/cart.rb | 3 ++- app/models/cart_item.rb | 3 +++ app/views/carts/index.html.erb | 14 ++++++++------ .../20140617171148_add_quantity_to_cart_item.rb | 5 +++++ db/schema.rb | 3 ++- 7 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20140617171148_add_quantity_to_cart_item.rb diff --git a/TODO b/TODO index 0820f7de..10294b45 100644 --- a/TODO +++ b/TODO @@ -48,7 +48,7 @@ ☐ 身為消費者,需要在訂單頁面看到正確的商品數量 ☐ 美化訂單畫面 ✔ 身為消費者,需要可以在購物車內刪除商品 @done(2014-06-17 10:11) @project(購物) - ☐ 身為消費者,可以選擇商品數量,加入購物車 + ✔ 身為消費者,可以選擇商品數量,加入購物車 @done(2014-06-18 08:33) @project(購物) ☐ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) ☐ 身為消費者, 不能將數量為0的商品加入購物車 ☐ 身為消費者, 能在account/orders看到過去的訂單記錄 diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index e6c14a6b..1e081b07 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -25,8 +25,7 @@ def add_to_cart @item_quantity = params[:item_quantity] if !current_cart.items.include?(@product) - current_cart.add_product_to_cart(@product, @item_quantity) - flash[:notice] = "你已成功將 #{@product.title} 加入購物車" + add_product_to_cart else flash[:warning] = "你的購物車內已有此物品" end @@ -34,4 +33,13 @@ def add_to_cart redirect_to :back end + + private + def add_product_to_cart + if current_cart.add_product_to_cart(@product, @item_quantity) + flash[:notice] = "你已成功將 #{@product.title} 加入購物車" + else + flash[:warning] = "你輸入的數量不正確" + end + end end diff --git a/app/models/cart.rb b/app/models/cart.rb index 8d049843..5063c690 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -7,7 +7,8 @@ def del_product_from_cart(product) end def add_product_to_cart(product, item_quantity) - items << product + cart_item = cart_items.build(product_id: product.id, quantity: item_quantity) + cart_item.save end def total_price diff --git a/app/models/cart_item.rb b/app/models/cart_item.rb index ddf0322b..6e848566 100644 --- a/app/models/cart_item.rb +++ b/app/models/cart_item.rb @@ -1,4 +1,7 @@ class CartItem < ActiveRecord::Base belongs_to :cart belongs_to :product + + validates :quantity, numericality: { only_integer: true, greater_than_or_equal_to: 0} + end diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index ef0380f0..9ba0e220 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -10,18 +10,20 @@ 商品資訊 單價 - 動作 + 數量 + - <% current_cart.items.each do |product| %> + <% current_cart.cart_items.each do |cart_item| %> - <%= product_render_photo(product) %> + <%= product_render_photo(cart_item.product) %> - <%= link_to(product.title, product_path(product)) %> + <%= link_to(cart_item.product.title, product_path(cart_item.product)) %> - <%= product.price %> - <%= link_to("刪除", del_from_cart_product_path(product), :method => :post, :class => "btn btn-primary") %> + <%= cart_item.product.price %> + <%= cart_item.quantity %> + <%= link_to("刪除", del_from_cart_product_path(cart_item.product), :method => :post, :class => "btn btn-primary") %> <% end %> diff --git a/db/migrate/20140617171148_add_quantity_to_cart_item.rb b/db/migrate/20140617171148_add_quantity_to_cart_item.rb new file mode 100644 index 00000000..25205eb4 --- /dev/null +++ b/db/migrate/20140617171148_add_quantity_to_cart_item.rb @@ -0,0 +1,5 @@ +class AddQuantityToCartItem < ActiveRecord::Migration + def change + add_column :cart_items, :quantity, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 80246c80..a07dd4eb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,13 +11,14 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140616132404) do +ActiveRecord::Schema.define(version: 20140617171148) do create_table "cart_items", force: true do |t| t.integer "cart_id" t.integer "product_id" t.datetime "created_at" t.datetime "updated_at" + t.integer "quantity", default: 0 end create_table "carts", force: true do |t| From f57ffa3a1c08df9e5e814b445fd1d5b235613dba Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 21:37:39 +0800 Subject: [PATCH 39/59] correct total price of cart --- TODO | 2 +- app/models/cart.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index 10294b45..e4baf681 100644 --- a/TODO +++ b/TODO @@ -49,7 +49,7 @@ ☐ 美化訂單畫面 ✔ 身為消費者,需要可以在購物車內刪除商品 @done(2014-06-17 10:11) @project(購物) ✔ 身為消費者,可以選擇商品數量,加入購物車 @done(2014-06-18 08:33) @project(購物) - ☐ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) + ✔ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) @done(2014-06-18 09:36) @project(購物) ☐ 身為消費者, 不能將數量為0的商品加入購物車 ☐ 身為消費者, 能在account/orders看到過去的訂單記錄 ☐ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index diff --git a/app/models/cart.rb b/app/models/cart.rb index 5063c690..db99e959 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -12,6 +12,6 @@ def add_product_to_cart(product, item_quantity) end def total_price - items.inject(0) {|sum, item| sum + item.price } + cart_items.inject(0) {|sum, item| sum + (item.product.price * item.quantity) } end end From 0ffd6058cf63c776f197c7645d440e90c91490f5 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 21:56:56 +0800 Subject: [PATCH 40/59] user can't add product with 0 quantity into cart --- TODO | 3 ++- app/models/cart_item.rb | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index e4baf681..89695ce3 100644 --- a/TODO +++ b/TODO @@ -50,13 +50,14 @@ ✔ 身為消費者,需要可以在購物車內刪除商品 @done(2014-06-17 10:11) @project(購物) ✔ 身為消費者,可以選擇商品數量,加入購物車 @done(2014-06-18 08:33) @project(購物) ✔ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) @done(2014-06-18 09:36) @project(購物) - ☐ 身為消費者, 不能將數量為0的商品加入購物車 + ✔ 身為消費者, 不能將數量為0的商品加入購物車 @done(2014-06-18 09:50) @project(購物) ☐ 身為消費者, 能在account/orders看到過去的訂單記錄 ☐ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index 系統訊息: ☐ 身為使用者, 我需要在頁面上看見包含error以外其他種類的通知訊息. + ☐ 身為使用者, 我需要在頁面上看到詳細的model validate error. 重構: diff --git a/app/models/cart_item.rb b/app/models/cart_item.rb index 6e848566..1520699a 100644 --- a/app/models/cart_item.rb +++ b/app/models/cart_item.rb @@ -2,6 +2,14 @@ class CartItem < ActiveRecord::Base belongs_to :cart belongs_to :product - validates :quantity, numericality: { only_integer: true, greater_than_or_equal_to: 0} + validates :quantity, numericality: { only_integer: true, greater_than_or_equal_to: 1} + validate :check_product_quantity + private + def check_product_quantity + + if product.quantity < quantity + errors.add(:quantity, "You order too many") + end + end end From 81cb94f2b638924d49a31bce9661e7f1867bf229 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 22:22:28 +0800 Subject: [PATCH 41/59] 1. User can get correct quantity on order page. 2. Delete cart after payment. --- TODO | 4 ++-- app/controllers/orders_controller.rb | 1 + app/models/order.rb | 8 ++++---- app/views/carts/checkout.html.erb | 8 +++++--- app/views/orders/show.html.erb | 2 ++ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/TODO b/TODO index 89695ce3..a31e5bf9 100644 --- a/TODO +++ b/TODO @@ -44,8 +44,8 @@ ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 ☐ 信用卡付款成功後也要收到通知信 ☐ 身為消費者, 可以從信中連結到訂單網頁 - ☐ 身為消費者,當訂單成立後,購物車需要清空 - ☐ 身為消費者,需要在訂單頁面看到正確的商品數量 + ✔ 身為消費者,當訂單成立後,購物車需要清空 @done(2014-06-18 10:21) @project(購物) + ✔ 身為消費者,需要在訂單頁面看到正確的商品數量 @done(2014-06-18 10:21) @project(購物) ☐ 美化訂單畫面 ✔ 身為消費者,需要可以在購物車內刪除商品 @done(2014-06-17 10:11) @project(購物) ✔ 身為消費者,可以選擇商品數量,加入購物車 @done(2014-06-18 08:33) @project(購物) diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index ac90f019..24e4e6e5 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -22,6 +22,7 @@ def pay_with_credit_card @order = current_user.orders.find_by_token(params[:id]) @order.set_payment_with!("credit_card") @order.make_payment! + current_cart.destroy! redirect_to root_path :notice => "成功完成付款" end diff --git a/app/models/order.rb b/app/models/order.rb index 089481e9..e5de7f8f 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -19,11 +19,11 @@ def generate_token end def build_item_cache_from_cart(cart) - cart.items.each do |cart_item| + cart.cart_items.each do |cart_item| item = items.build - item.product_name = cart_item.title - item.quantity = 1 - item.price = cart_item.price + item.product_name = cart_item.product.title + item.quantity = cart_item.quantity + item.price = cart_item.product.price item.save end end diff --git a/app/views/carts/checkout.html.erb b/app/views/carts/checkout.html.erb index b1904445..962c02c3 100644 --- a/app/views/carts/checkout.html.erb +++ b/app/views/carts/checkout.html.erb @@ -7,17 +7,19 @@ 商品明細 + 數量 單價 - <% current_cart.items.each do |product| %> + <% current_cart.cart_items.each do |cart_item| %> - <%= link_to(product.title, admin_product_path(product)) %> + <%= link_to(cart_item.product.title, admin_product_path(cart_item.product)) %> - <%= product.price %> + <%= cart_item.quantity %> + <%= cart_item.product.price %> <% end %> diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index be21a55b..bbb81b9c 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -7,6 +7,7 @@ 商品明細 + 數量 單價 @@ -16,6 +17,7 @@ <%= order_item.product_name %> + <%= order_item.quantity %> <%= order_item.price %> <% end %> From 1734f0d32b28800928d9e8bf8fe55385fbb5dc95 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 22:46:18 +0800 Subject: [PATCH 42/59] user can check order history at account/orders --- TODO | 2 +- .../javascripts/account/orders.js.coffee | 3 ++ .../stylesheets/account/orders.css.scss | 3 ++ app/controllers/account/orders_controller.rb | 7 ++++ app/helpers/account/orders_helper.rb | 17 +++++++++ app/views/account/orders/index.html.erb | 38 +++++++++++++++++++ config/routes.rb | 4 ++ .../account/orders_controller_test.rb | 7 ++++ test/helpers/account/orders_helper_test.rb | 4 ++ 9 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/account/orders.js.coffee create mode 100644 app/assets/stylesheets/account/orders.css.scss create mode 100644 app/controllers/account/orders_controller.rb create mode 100644 app/helpers/account/orders_helper.rb create mode 100644 app/views/account/orders/index.html.erb create mode 100644 test/controllers/account/orders_controller_test.rb create mode 100644 test/helpers/account/orders_helper_test.rb diff --git a/TODO b/TODO index a31e5bf9..206ff607 100644 --- a/TODO +++ b/TODO @@ -51,7 +51,7 @@ ✔ 身為消費者,可以選擇商品數量,加入購物車 @done(2014-06-18 08:33) @project(購物) ✔ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) @done(2014-06-18 09:36) @project(購物) ✔ 身為消費者, 不能將數量為0的商品加入購物車 @done(2014-06-18 09:50) @project(購物) - ☐ 身為消費者, 能在account/orders看到過去的訂單記錄 + ✔ 身為消費者, 能在account/orders看到過去的訂單記錄 @done(2014-06-18 10:45) @project(購物) ☐ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index diff --git a/app/assets/javascripts/account/orders.js.coffee b/app/assets/javascripts/account/orders.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/account/orders.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/stylesheets/account/orders.css.scss b/app/assets/stylesheets/account/orders.css.scss new file mode 100644 index 00000000..782d07c6 --- /dev/null +++ b/app/assets/stylesheets/account/orders.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the account::orders controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/account/orders_controller.rb b/app/controllers/account/orders_controller.rb new file mode 100644 index 00000000..1380fda9 --- /dev/null +++ b/app/controllers/account/orders_controller.rb @@ -0,0 +1,7 @@ +class Account::OrdersController < ApplicationController + before_action :authenticate_user! + + def index + @orders = current_user.orders + end +end diff --git a/app/helpers/account/orders_helper.rb b/app/helpers/account/orders_helper.rb new file mode 100644 index 00000000..2739e98a --- /dev/null +++ b/app/helpers/account/orders_helper.rb @@ -0,0 +1,17 @@ +module Account::OrdersHelper + def render_account_order_total(order) + order.total + end + + def render_account_order_paid(order) + if order.paid + "已付款" + else + "未付款" + end + end + + def render_account_order_created_at(order) + order.created_at + end +end diff --git a/app/views/account/orders/index.html.erb b/app/views/account/orders/index.html.erb new file mode 100644 index 00000000..1ccdbe3a --- /dev/null +++ b/app/views/account/orders/index.html.erb @@ -0,0 +1,38 @@ +
    + + + + + + + + + + + <% @orders.each_with_index do |order, idx| %> + + + + + + + <% end %> + +
    + # + + 總價 + + 付款狀態 + + 訂單日期 +
    + <%= idx+1 %> + + <%= render_account_order_total(order) %> + + <%= render_account_order_paid(order) %> + + <%= render_account_order_created_at(order) %> +
    +
    diff --git a/config/routes.rb b/config/routes.rb index a5306369..880051e0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,4 +23,8 @@ get :pay_with_credit_card end end + + namespace :account do + resources :orders + end end diff --git a/test/controllers/account/orders_controller_test.rb b/test/controllers/account/orders_controller_test.rb new file mode 100644 index 00000000..b0419411 --- /dev/null +++ b/test/controllers/account/orders_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class Account::OrdersControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/helpers/account/orders_helper_test.rb b/test/helpers/account/orders_helper_test.rb new file mode 100644 index 00000000..60734209 --- /dev/null +++ b/test/helpers/account/orders_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class Account::OrdersHelperTest < ActionView::TestCase +end From 5de5b84b5d0632ca607b3070cf9491f44a1bcaed Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 18 Jun 2014 22:52:24 +0800 Subject: [PATCH 43/59] after pay order, redirect to account/orders --- TODO | 2 +- app/controllers/orders_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index 206ff607..c0c4b0d3 100644 --- a/TODO +++ b/TODO @@ -52,7 +52,7 @@ ✔ 身為消費者, 能看在購物車看到正確的總額(商品數量X商品價格) @done(2014-06-18 09:36) @project(購物) ✔ 身為消費者, 不能將數量為0的商品加入購物車 @done(2014-06-18 09:50) @project(購物) ✔ 身為消費者, 能在account/orders看到過去的訂單記錄 @done(2014-06-18 10:45) @project(購物) - ☐ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index + ✔ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index @done(2014-06-18 10:51) @project(購物) 系統訊息: diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 24e4e6e5..ea1da121 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -23,7 +23,7 @@ def pay_with_credit_card @order.set_payment_with!("credit_card") @order.make_payment! current_cart.destroy! - redirect_to root_path :notice => "成功完成付款" + redirect_to account_orders_path :notice => "成功完成付款" end From fbcae0d8a5edb9c21a2c0b8dfaacfe0eda2ef276 Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 19 Jun 2014 20:57:05 +0800 Subject: [PATCH 44/59] 1. As a admin, he can see all orders at admin/orders 2. As a admin, he can translate order state at admin/orders#show and should follow the rule of state machine. --- TODO | 8 +-- app/assets/javascripts/admin/orders.js.coffee | 3 + app/assets/stylesheets/admin/orders.css.scss | 3 + app/controllers/admin/orders_controller.rb | 45 +++++++++++++ app/helpers/account/orders_helper.rb | 15 ----- app/helpers/admin/orders_helper.rb | 2 + app/helpers/orders_helper.rb | 19 ++++++ app/models/order.rb | 6 +- app/views/account/orders/index.html.erb | 6 +- app/views/admin/orders/index.html.erb | 41 ++++++++++++ app/views/admin/orders/show.html.erb | 67 +++++++++++++++++++ config/routes.rb | 8 +++ .../admin/orders_controller_test.rb | 7 ++ test/helpers/admin/orders_helper_test.rb | 4 ++ 14 files changed, 209 insertions(+), 25 deletions(-) create mode 100644 app/assets/javascripts/admin/orders.js.coffee create mode 100644 app/assets/stylesheets/admin/orders.css.scss create mode 100644 app/controllers/admin/orders_controller.rb create mode 100644 app/helpers/admin/orders_helper.rb create mode 100644 app/views/admin/orders/index.html.erb create mode 100644 app/views/admin/orders/show.html.erb create mode 100644 test/controllers/admin/orders_controller_test.rb create mode 100644 test/helpers/admin/orders_helper_test.rb diff --git a/TODO b/TODO index c0c4b0d3..29fba8e2 100644 --- a/TODO +++ b/TODO @@ -27,9 +27,9 @@ ✔ 管理者身份必須要被分為admin/user @done(2014-06-11 10:12) ✔ 身為一般使用者, 需要能看到所有產品 @done(2014-06-15 03:02) - ☐ 身為商家的管理者,可以在後台看到所有訂單 - ☐ 身為商家的管理者,可以在後台的訂單列表看到每張訂單的狀態 - ☐ 身為商家的管理者,可以在後台每張訂單內按照狀態圖改變狀態 + ✔ 身為商家的管理者,可以在後台看到所有訂單 @done(2014-06-19 08:55) + ✔ 身為商家的管理者,可以在後台的訂單列表看到每張訂單的狀態 @done(2014-06-19 08:55) + ✔ 身為商家的管理者,可以在後台每張訂單內按照狀態圖改變狀態 @done(2014-06-19 08:55) @@ -62,4 +62,4 @@ 重構: ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) - ☐ + ☐ 簡化admin/order#show狀態轉換的code, 包含viwe, controller diff --git a/app/assets/javascripts/admin/orders.js.coffee b/app/assets/javascripts/admin/orders.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/admin/orders.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/stylesheets/admin/orders.css.scss b/app/assets/stylesheets/admin/orders.css.scss new file mode 100644 index 00000000..7ed90c7e --- /dev/null +++ b/app/assets/stylesheets/admin/orders.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the admin::orders controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/admin/orders_controller.rb b/app/controllers/admin/orders_controller.rb new file mode 100644 index 00000000..550926b7 --- /dev/null +++ b/app/controllers/admin/orders_controller.rb @@ -0,0 +1,45 @@ +class Admin::OrdersController < ApplicationController + before_action :authenticate_user! + before_action :admin_required + before_action :find_order, except: [:index] + + def show + + @order_info = @order.info + @order_items = @order.items + end + + def index + @orders = Order.all + end + + def ship + @order.ship + save_and_redirect_to_show + end + + def deliver + @order.deliver + save_and_redirect_to_show + end + + def cancel_order + @order.cancel_order + save_and_redirect_to_show + end + + def return_good + @order.return_good + save_and_redirect_to_show + end + + private + def find_order + @order = Order.find(params[:id]) + end + + def save_and_redirect_to_show + @order.save + redirect_to admin_order_path(@order) + end +end diff --git a/app/helpers/account/orders_helper.rb b/app/helpers/account/orders_helper.rb index 2739e98a..6f690c4e 100644 --- a/app/helpers/account/orders_helper.rb +++ b/app/helpers/account/orders_helper.rb @@ -1,17 +1,2 @@ module Account::OrdersHelper - def render_account_order_total(order) - order.total - end - - def render_account_order_paid(order) - if order.paid - "已付款" - else - "未付款" - end - end - - def render_account_order_created_at(order) - order.created_at - end end diff --git a/app/helpers/admin/orders_helper.rb b/app/helpers/admin/orders_helper.rb new file mode 100644 index 00000000..863374ff --- /dev/null +++ b/app/helpers/admin/orders_helper.rb @@ -0,0 +1,2 @@ +module Admin::OrdersHelper +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb index 443227fd..66bbf267 100644 --- a/app/helpers/orders_helper.rb +++ b/app/helpers/orders_helper.rb @@ -1,2 +1,21 @@ module OrdersHelper + def render_order_total(order) + order.total + end + + def render_order_paid(order) + if order.paid + "已付款" + else + "未付款" + end + end + + def render_order_created_at(order) + order.created_at + end + + def render_order_aasm_state(order) + order.aasm_state + end end diff --git a/app/models/order.rb b/app/models/order.rb index e5de7f8f..d762e743 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -52,9 +52,9 @@ def calculate_total!(current_cart) transitions :from => :shipping, :to => :shipped end - state :order_cancelled - event :cancell_order do - transitions :from => [:order_placed, :paid ], :to => :order_cancelled + state :order_canceled + event :cancel_order do + transitions :from => [:order_placed, :paid ], :to => :order_canceled end state :good_returned diff --git a/app/views/account/orders/index.html.erb b/app/views/account/orders/index.html.erb index 1ccdbe3a..0c2121e4 100644 --- a/app/views/account/orders/index.html.erb +++ b/app/views/account/orders/index.html.erb @@ -23,13 +23,13 @@ <%= idx+1 %> - <%= render_account_order_total(order) %> + <%= render_order_total(order) %> - <%= render_account_order_paid(order) %> + <%= render_order_aasm_state(order) %> - <%= render_account_order_created_at(order) %> + <%= render_order_created_at(order) %> <% end %> diff --git a/app/views/admin/orders/index.html.erb b/app/views/admin/orders/index.html.erb new file mode 100644 index 00000000..b27b2ee3 --- /dev/null +++ b/app/views/admin/orders/index.html.erb @@ -0,0 +1,41 @@ +
    + + + + + + + + + + + <% @orders.each_with_index do |order, idx| %> + + + + + + + + <% end %> + +
    + # + + 總價 + + 狀態 + + 訂單日期 +
    + <%= idx+1 %> + + <%= render_order_total(order) %> + + <%= render_order_aasm_state(order) %> + + <%= render_order_created_at(order) %> + + <%= link_to("前往", admin_order_path(order), class: "btn btn-primary") %> +
    +
    diff --git a/app/views/admin/orders/show.html.erb b/app/views/admin/orders/show.html.erb new file mode 100644 index 00000000..4a7eb2b4 --- /dev/null +++ b/app/views/admin/orders/show.html.erb @@ -0,0 +1,67 @@ +
    +
    +
    +

    訂單明細

    + + + + + + + + + + <% @order_items.each do |order_item| %> + + + + + + <% end %> + +
    商品明細數量單價
    + <%= order_item.product_name %> + <%= order_item.quantity %> <%= order_item.price %>
    +
    + + 總計 <%= @order.total %> NTD + +
    +
    +

    寄送資訊

    + + + + + + + + + + + + + + + +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    +

    狀態:<%= @order.aasm_state %>

    + <% if @order.may_ship? %> + <%= link_to("出貨", ship_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> + <% if @order.may_deliver? %> + <%= link_to("到貨", deliver_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> + <% if @order.may_cancel_order? %> + <%= link_to("取消訂單", cancel_order_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> + <% if @order.may_return_good? %> + <%= link_to("退貨", return_good_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> +
    +
    +
    diff --git a/config/routes.rb b/config/routes.rb index 880051e0..963b4589 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,14 @@ devise_for :users namespace :admin do resources :products + resources :orders do + member do + post :ship + post :deliver + post :cancel_order + post :return_good + end + end end resources :products do diff --git a/test/controllers/admin/orders_controller_test.rb b/test/controllers/admin/orders_controller_test.rb new file mode 100644 index 00000000..8af7f0c9 --- /dev/null +++ b/test/controllers/admin/orders_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class Admin::OrdersControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/helpers/admin/orders_helper_test.rb b/test/helpers/admin/orders_helper_test.rb new file mode 100644 index 00000000..8511d6d4 --- /dev/null +++ b/test/helpers/admin/orders_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class Admin::OrdersHelperTest < ActionView::TestCase +end From 96239c19e130f0552a261a9d6f70ac86790ce85d Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 19 Jun 2014 21:05:51 +0800 Subject: [PATCH 45/59] format the html files and add div of container class in some views --- app/views/account/orders/index.html.erb | 2 +- app/views/admin/orders/show.html.erb | 126 ++++++++++----------- app/views/carts/checkout.html.erb | 123 +++++++++----------- app/views/carts/index.html.erb | 47 ++++---- app/views/orders/show.html.erb | 143 ++++++++++-------------- 5 files changed, 194 insertions(+), 247 deletions(-) diff --git a/app/views/account/orders/index.html.erb b/app/views/account/orders/index.html.erb index 0c2121e4..9097c9b7 100644 --- a/app/views/account/orders/index.html.erb +++ b/app/views/account/orders/index.html.erb @@ -9,7 +9,7 @@ 總價 - 付款狀態 + 訂單狀態 訂單日期 diff --git a/app/views/admin/orders/show.html.erb b/app/views/admin/orders/show.html.erb index 4a7eb2b4..94a35b8e 100644 --- a/app/views/admin/orders/show.html.erb +++ b/app/views/admin/orders/show.html.erb @@ -1,67 +1,67 @@
    -
    -
    -

    訂單明細

    - - - - - - - - - - <% @order_items.each do |order_item| %> - - - - - - <% end %> - -
    商品明細數量單價
    - <%= order_item.product_name %> - <%= order_item.quantity %> <%= order_item.price %>
    -
    - - 總計 <%= @order.total %> NTD - +
    +
    +

    訂單明細

    + + + + + + + + + + <% @order_items.each do |order_item| %> + + + + + + <% end %> + +
    商品明細數量單價
    + <%= order_item.product_name %> + <%= order_item.quantity %> <%= order_item.price %>
    +
    + + 總計 <%= @order.total %> NTD + +
    +
    +

    寄送資訊

    + + + + + + + + + + + + + + + +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    +

    狀態:<%= @order.aasm_state %>

    + <% if @order.may_ship? %> + <%= link_to("出貨", ship_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> + <% if @order.may_deliver? %> + <%= link_to("到貨", deliver_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> + <% if @order.may_cancel_order? %> + <%= link_to("取消訂單", cancel_order_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %> + <% if @order.may_return_good? %> + <%= link_to("退貨", return_good_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <% end %>
    -
    -

    寄送資訊

    - - - - - - - - - - - - - - - -
    訂購人
    - <%= @order_info.billing_name %> - <%= @order_info.billing_address %> -
    訂購人
    - <%= @order_info.billing_name %> - <%= @order_info.billing_address %> -
    -

    狀態:<%= @order.aasm_state %>

    - <% if @order.may_ship? %> - <%= link_to("出貨", ship_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> - <% end %> - <% if @order.may_deliver? %> - <%= link_to("到貨", deliver_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> - <% end %> - <% if @order.may_cancel_order? %> - <%= link_to("取消訂單", cancel_order_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> - <% end %> - <% if @order.may_return_good? %> - <%= link_to("退貨", return_good_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> - <% end %>
    -
    diff --git a/app/views/carts/checkout.html.erb b/app/views/carts/checkout.html.erb index 962c02c3..a737d88e 100644 --- a/app/views/carts/checkout.html.erb +++ b/app/views/carts/checkout.html.erb @@ -1,76 +1,57 @@ -
    -
    - -

    購物明細

    - - - - - - - - - - - <% current_cart.cart_items.each do |cart_item| %> - - - - - - <% end %> - - -
    商品明細數量單價
    - - <%= link_to(cart_item.product.title, admin_product_path(cart_item.product)) %> - <%= cart_item.quantity %> <%= cart_item.product.price %>
    - -
    - - 總計 <%= render_cart_total_price(current_cart) %> NTD - -
    - -
    - -

    訂單資訊

    - - -
    - - <%= simple_form_for @order do |f| %> - - <%= f.simple_fields_for :info do |c| %> - - 訂購人 - -
    - <%= c.input :billing_name %> -
    -
    - <%= c.input :billing_address %> -
    - - 收貨人 -
    - <%= c.input :shipping_name %> +
    +
    +
    +

    購物明細

    + + + + + + + + + + <% current_cart.cart_items.each do |cart_item| %> + + + + + + <% end %> + +
    商品明細數量單價
    + <%= link_to(cart_item.product.title, admin_product_path(cart_item.product)) %> + <%= cart_item.quantity %> <%= cart_item.product.price %>
    +
    + + 總計 <%= render_cart_total_price(current_cart) %> NTD +
    -
    - <%= c.input :shipping_address %> +
    +

    訂單資訊

    +
    + <%= simple_form_for @order do |f| %> + <%= f.simple_fields_for :info do |c| %> + 訂購人 +
    + <%= c.input :billing_name %> +
    +
    + <%= c.input :billing_address %> +
    + 收貨人 +
    + <%= c.input :shipping_name %> +
    +
    + <%= c.input :shipping_address %> +
    + <% end %> +
    + <%= f.submit "生成訂單", :class => "btn btn-primary btn-lg btn-danger pull-right", :disable_with => 'Submiting...' %> +
    + <% end %>
    - <% end %> - -
    - <%= f.submit "生成訂單", :class => "btn btn-primary btn-lg btn-danger pull-right", :disable_with => 'Submiting...' %>
    - - <% end %>
    - - - -
    - -
    diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 9ba0e220..65f8fed6 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -1,49 +1,40 @@ -
    +
    -
    - -

    購物車

    - - - - - - - - - - - - - <% current_cart.cart_items.each do |cart_item| %> +
    +

    購物車

    +
    商品資訊單價數量
    + + + + + + + + + + + <% current_cart.cart_items.each do |cart_item| %> - <% end %> - + <% end %>
    商品資訊單價數量
    <%= product_render_photo(cart_item.product) %> - <%= link_to(cart_item.product.title, product_path(cart_item.product)) %> + <%= link_to(cart_item.product.title, product_path(cart_item.product)) %> <%= cart_item.product.price %> <%= cart_item.quantity %> <%= link_to("刪除", del_from_cart_product_path(cart_item.product), :method => :post, :class => "btn btn-primary") %>
    -
    - 總計 <%= render_cart_total_price(current_cart) %> NTD + 總計 <%= render_cart_total_price(current_cart) %> NTD
    -
    - <%= link_to("確認結賬", checkout_cart_path(current_cart) , :method => :post , :class => "btn btn-primary btn-lg btn-danger pull-right") %> + <%= link_to("確認結賬", checkout_cart_path(current_cart) , :method => :post , :class => "btn btn-primary btn-lg btn-danger pull-right") %>
    - -
    - -
    diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb index bbb81b9c..8805bbbd 100644 --- a/app/views/orders/show.html.erb +++ b/app/views/orders/show.html.erb @@ -1,87 +1,62 @@ -
    -
    - -

    訂單明細

    - - - - - - - - - - - <% @order_items.each do |order_item| %> - - - - - - <% end %> - - -
    商品明細數量單價
    - <%= order_item.product_name %> - <%= order_item.quantity %> <%= order_item.price %>
    - -
    - - 總計 <%= @order.total %> NTD - -
    - -
    - -

    寄送資訊

    - - - - - - - - - - - - - - - - - - - - - - - -
    訂購人
    - <%= @order_info.billing_name %> - <%= @order_info.billing_address %> -
    訂購人
    - <%= @order_info.billing_name %> - <%= @order_info.billing_address %> -
    - - - <% if !@order.paid? %> - -
    - <%= link_to("以信用卡付款", pay_with_credit_card_order_path(@order.token), :class => "btn btn-primary btn-lg btn-danger ") %> - - <%= link_to("以 ATM 付款", "#", :class => "btn btn-primary btn-lg btn-danger ") %> +
    +
    +
    +

    訂單明細

    + + + + + + + + + + <% @order_items.each do |order_item| %> + + + + + + <% end %> + +
    商品明細數量單價
    + <%= order_item.product_name %> + <%= order_item.quantity %> <%= order_item.price %>
    +
    + + 總計 <%= @order.total %> NTD + +
    +
    +

    寄送資訊

    + + + + + + + + + + + + + + + +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    + <% if !@order.paid? %> +
    + <%= link_to("以信用卡付款", pay_with_credit_card_order_path(@order.token), :class => "btn btn-primary btn-lg btn-danger ") %> + <%= link_to("以 ATM 付款", "#", :class => "btn btn-primary btn-lg btn-danger ") %> +
    + <% else %> + 此訂單已完成付款 + <% end %>
    - - <% else %> - - 此訂單已完成付款 - - <% end %> - - - -
    - -
    From 485da891d08841017c2b41b2663f51003ead8282 Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 19 Jun 2014 21:09:01 +0800 Subject: [PATCH 46/59] add TODO item --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 29fba8e2..4be1b0da 100644 --- a/TODO +++ b/TODO @@ -63,3 +63,4 @@ 重構: ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) ☐ 簡化admin/order#show狀態轉換的code, 包含viwe, controller + ☐ 將加入/移除購物車功能, 轉移到cart_items controller相對應的create/destroy action From c40a563b5af07e52503bc2ca37d419a2ece45045 Mon Sep 17 00:00:00 2001 From: orga Date: Fri, 20 Jun 2014 01:09:32 +0800 Subject: [PATCH 47/59] update nav_bar: add more links --- app/views/common/_nav_bar.html.erb | 35 ++++++++++++++------- app/views/devise/registrations/new.html.erb | 31 +++++++++--------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/app/views/common/_nav_bar.html.erb b/app/views/common/_nav_bar.html.erb index 7fe9e355..6852ee22 100644 --- a/app/views/common/_nav_bar.html.erb +++ b/app/views/common/_nav_bar.html.erb @@ -4,19 +4,30 @@
    diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index c347084c..5ffdd534 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -1,17 +1,16 @@ -

    Sign up

    +
    + <%= simple_form_for(resource, :as => resource_name, html: { class: 'form-signin', role: 'form' }, :url => registration_path(resource_name)) do |f| %> + <%= f.error_notification %> + +
    + <%= f.input :email, :required => true, :autofocus => true, :input_html => {:class => "form-control"} %> + <%= f.input :password, :required => true, :input_html => {:class => "form-control"} %> + <%= f.input :password_confirmation, :required => true, :input_html => {:class => "form-control"} %> +
    -<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name) do |f| %> - <%= f.error_notification %> - -
    - <%= f.input :email, :required => true, :autofocus => true %> - <%= f.input :password, :required => true %> - <%= f.input :password_confirmation, :required => true %> -
    - -
    - <%= f.button :submit, "Sign up" %> -
    -<% end %> - -<%= render "devise/shared/links" %> +
    + <%= f.button :submit, "Sign up", class: "btn btn-lg btn-primary btn-block" %> +
    + <%= render "devise/shared/links" %> + <% end %> +
    From 284b71f471a77d8d0655b02eba7aa6d1cd6cfa4f Mon Sep 17 00:00:00 2001 From: orga Date: Fri, 20 Jun 2014 02:46:06 +0800 Subject: [PATCH 48/59] refactor: using reflection for order state transition --- TODO | 2 +- app/controllers/admin/orders_controller.rb | 19 ++----------------- app/helpers/admin/orders_helper.rb | 3 +++ app/views/admin/orders/show.html.erb | 8 ++++---- config/routes.rb | 1 + 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/TODO b/TODO index 4be1b0da..7f81b61b 100644 --- a/TODO +++ b/TODO @@ -62,5 +62,5 @@ 重構: ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) - ☐ 簡化admin/order#show狀態轉換的code, 包含viwe, controller + ✔ 簡化admin/order#show狀態轉換的code, 包含viwe, controller @done(2014-06-20 02:44) @project(重構) ☐ 將加入/移除購物車功能, 轉移到cart_items controller相對應的create/destroy action diff --git a/app/controllers/admin/orders_controller.rb b/app/controllers/admin/orders_controller.rb index 550926b7..0ac0769b 100644 --- a/app/controllers/admin/orders_controller.rb +++ b/app/controllers/admin/orders_controller.rb @@ -13,23 +13,8 @@ def index @orders = Order.all end - def ship - @order.ship - save_and_redirect_to_show - end - - def deliver - @order.deliver - save_and_redirect_to_show - end - - def cancel_order - @order.cancel_order - save_and_redirect_to_show - end - - def return_good - @order.return_good + def state_transition + @order.send(params[:event]) save_and_redirect_to_show end diff --git a/app/helpers/admin/orders_helper.rb b/app/helpers/admin/orders_helper.rb index 863374ff..145257ce 100644 --- a/app/helpers/admin/orders_helper.rb +++ b/app/helpers/admin/orders_helper.rb @@ -1,2 +1,5 @@ module Admin::OrdersHelper + def render_state_transition_btn(label, order, event) + link_to(label, state_transition_admin_order_path(order, event: event), method: :post, :class => "btn btn-primary") + end end diff --git a/app/views/admin/orders/show.html.erb b/app/views/admin/orders/show.html.erb index 94a35b8e..9c77d30a 100644 --- a/app/views/admin/orders/show.html.erb +++ b/app/views/admin/orders/show.html.erb @@ -51,16 +51,16 @@

    狀態:<%= @order.aasm_state %>

    <% if @order.may_ship? %> - <%= link_to("出貨", ship_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <%= render_state_transition_btn("出貨", @order, :ship) %> <% end %> <% if @order.may_deliver? %> - <%= link_to("到貨", deliver_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <%= render_state_transition_btn("到貨", @order, :deliver) %> <% end %> <% if @order.may_cancel_order? %> - <%= link_to("取消訂單", cancel_order_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <%= render_state_transition_btn("取消訂單", @order, :cancel_order) %> <% end %> <% if @order.may_return_good? %> - <%= link_to("退貨", return_good_admin_order_path(@order), method: :post, :class => "btn btn-primary") %> + <%= render_state_transition_btn("退貨", @order, :return_good) %> <% end %>
    diff --git a/config/routes.rb b/config/routes.rb index 963b4589..306e4cff 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ post :deliver post :cancel_order post :return_good + post :state_transition end end end From 0ad8b8645882b29d736c8f01d940a9f156fe538a Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 22 Jun 2014 23:00:26 +0800 Subject: [PATCH 49/59] create cart_times controller and move add/delete product to cart to cart_items controller. Add update quantity feature in Cart index page --- TODO | 2 +- app/assets/javascripts/cart_items.js.coffee | 3 ++ app/assets/stylesheets/cart_items.css.scss | 3 ++ app/controllers/cart_items_controller.rb | 48 +++++++++++++++++++ app/controllers/products_controller.rb | 24 +--------- app/helpers/cart_items_helper.rb | 2 + app/models/cart.rb | 8 ---- app/views/carts/index.html.erb | 16 +++++-- app/views/products/show.html.erb | 5 +- config/routes.rb | 2 + .../controllers/cart_items_controller_test.rb | 7 +++ test/helpers/cart_items_helper_test.rb | 4 ++ 12 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 app/assets/javascripts/cart_items.js.coffee create mode 100644 app/assets/stylesheets/cart_items.css.scss create mode 100644 app/controllers/cart_items_controller.rb create mode 100644 app/helpers/cart_items_helper.rb create mode 100644 test/controllers/cart_items_controller_test.rb create mode 100644 test/helpers/cart_items_helper_test.rb diff --git a/TODO b/TODO index 7f81b61b..acde63da 100644 --- a/TODO +++ b/TODO @@ -63,4 +63,4 @@ 重構: ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) ✔ 簡化admin/order#show狀態轉換的code, 包含viwe, controller @done(2014-06-20 02:44) @project(重構) - ☐ 將加入/移除購物車功能, 轉移到cart_items controller相對應的create/destroy action + ✔ 將加入/移除購物車功能, 轉移到cart_items controller相對應的create/destroy action @done(2014-06-22 10:58) @project(重構) diff --git a/app/assets/javascripts/cart_items.js.coffee b/app/assets/javascripts/cart_items.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/cart_items.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/stylesheets/cart_items.css.scss b/app/assets/stylesheets/cart_items.css.scss new file mode 100644 index 00000000..c8ba3800 --- /dev/null +++ b/app/assets/stylesheets/cart_items.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the cart_items controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/cart_items_controller.rb b/app/controllers/cart_items_controller.rb new file mode 100644 index 00000000..2a498fb0 --- /dev/null +++ b/app/controllers/cart_items_controller.rb @@ -0,0 +1,48 @@ +class CartItemsController < ApplicationController + + def create + @cart_item = current_cart.cart_items.build(cart_item_params) + + if !current_cart.items.include?(@cart_item.product) + add_product_to_cart + else + flash[:warning] = "你的購物車內已有此物品" + end + + redirect_to :back + end + + def update + @cart_item = current_cart.cart_items.find(params[:id]) + @cart_item.update(cart_item_params) + + redirect_to carts_path + end + + def destroy + @cart_item = current_cart.cart_items.find(params[:id]) + if @cart_item.present? + @cart_item.destroy + flash[:notice] = "你已成功將 #{@cart_item.product.title} 移除" + else + flash[:warning] = "你的購物車沒有此物品" + end + + redirect_to carts_path + end + + private + def add_product_to_cart + + + if @cart_item.save + flash[:notice] = "你已成功將 #{@cart_item.product.title} 加入購物車" + else + flash[:warning] = "你輸入的數量不正確" + end + end + + def cart_item_params + params.require(:cart_item).permit(:quantity, :product_id) + end +end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 1e081b07..0c2569d9 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -5,6 +5,7 @@ def index def show @product = Product.find(params[:id]) + @cart_item = current_cart.cart_items.build(quantity: 1) end def del_from_cart @@ -19,27 +20,4 @@ def del_from_cart redirect_to carts_path end - def add_to_cart - - @product = Product.find(params[:id]) - @item_quantity = params[:item_quantity] - - if !current_cart.items.include?(@product) - add_product_to_cart - else - flash[:warning] = "你的購物車內已有此物品" - end - - redirect_to :back - - end - - private - def add_product_to_cart - if current_cart.add_product_to_cart(@product, @item_quantity) - flash[:notice] = "你已成功將 #{@product.title} 加入購物車" - else - flash[:warning] = "你輸入的數量不正確" - end - end end diff --git a/app/helpers/cart_items_helper.rb b/app/helpers/cart_items_helper.rb new file mode 100644 index 00000000..f30f6834 --- /dev/null +++ b/app/helpers/cart_items_helper.rb @@ -0,0 +1,2 @@ +module CartItemsHelper +end diff --git a/app/models/cart.rb b/app/models/cart.rb index db99e959..3e7f1d98 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -2,14 +2,6 @@ class Cart < ActiveRecord::Base has_many :cart_items, :dependent => :destroy has_many :items, :through => :cart_items, :source => :product - def del_product_from_cart(product) - items.delete(product) - end - - def add_product_to_cart(product, item_quantity) - cart_item = cart_items.build(product_id: product.id, quantity: item_quantity) - cart_item.save - end def total_price cart_items.inject(0) {|sum, item| sum + (item.product.price * item.quantity) } diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb index 65f8fed6..dbd0bd57 100644 --- a/app/views/carts/index.html.erb +++ b/app/views/carts/index.html.erb @@ -20,15 +20,25 @@ <%= link_to(cart_item.product.title, product_path(cart_item.product)) %> <%= cart_item.product.price %> - <%= cart_item.quantity %> - <%= link_to("刪除", del_from_cart_product_path(cart_item.product), :method => :post, :class => "btn btn-primary") %> + + <%= simple_form_for cart_item, html: { role: 'form', class: 'form-inline' } do |f| %> +
    + <%= f.input :quantity, label: false, collection: 1..cart_item.product.quantity, :input_html => {:class => "form-control"} %> +
    +
    + <%= f.button :submit, :value => "更新", :disable_with => 'Submiting....', class: "btn btn-primary" %> +
    + <% end %> + + <%= link_to("刪除", cart_item_path(cart_item), :method => :delete, :class => "btn btn-primary") %> <% end %>
    - 總計 <%= render_cart_total_price(current_cart) %> NTD + 總計 <%= render_cart_total_price(current_cart) %> NTD +

    diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb index 21ff951c..f2f38dd1 100644 --- a/app/views/products/show.html.erb +++ b/app/views/products/show.html.erb @@ -13,9 +13,10 @@

    <%= @product.description %>

    庫存:<%= @product.quantity %>

    價格:<%= @product.price %>

    - <%= simple_form_for @product, url: add_to_cart_product_path(@product), method: :post, html: { role: 'form', class: 'form-inline' } do |f| %> + <%= simple_form_for @cart_item, html: { role: 'form', class: 'form-inline' } do |f| %>
    - <%= f.input :item_quantity, label: "數量:", as: :fake, collection: 1..@product.quantity, :input_html => {:class => "form-control"} %> + <%= f.input :quantity, label: "數量:", collection: 1..@product.quantity, :input_html => {:class => "form-control"} %> + <%= f.input :product_id, as: :hidden, :input_html => { :value => @product.id }%>
    <%= f.button :submit, :value => "加入購物車", :disable_with => 'Submiting....', class: "btn btn-primary" %> diff --git a/config/routes.rb b/config/routes.rb index 306e4cff..35f957d3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -36,4 +36,6 @@ namespace :account do resources :orders end + + resources :cart_items end diff --git a/test/controllers/cart_items_controller_test.rb b/test/controllers/cart_items_controller_test.rb new file mode 100644 index 00000000..76b2b022 --- /dev/null +++ b/test/controllers/cart_items_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CartItemsControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/helpers/cart_items_helper_test.rb b/test/helpers/cart_items_helper_test.rb new file mode 100644 index 00000000..4cfc7e99 --- /dev/null +++ b/test/helpers/cart_items_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class CartItemsHelperTest < ActionView::TestCase +end From 2f3ebda34ba152da89df7ba281451bab66439ec4 Mon Sep 17 00:00:00 2001 From: orga Date: Sun, 22 Jun 2014 23:02:39 +0800 Subject: [PATCH 50/59] update gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 389fd328..0401ac99 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ # Ignore image files /public/uploads + +# Ignore rubymine config file +.idea From 560e669ac14024d30e034998dc4bbf5e4a345267 Mon Sep 17 00:00:00 2001 From: orga Date: Mon, 23 Jun 2014 21:13:43 +0800 Subject: [PATCH 51/59] class 3 content --- Gemfile | 7 +++ Gemfile.lock | 24 +++++++++ app/assets/javascripts/application.js | 1 + app/assets/javascripts/card_charges.js.coffee | 3 ++ app/assets/javascripts/orders.js.coffee | 32 ++++++++++++ app/assets/stylesheets/card_charges.css.scss | 3 ++ app/controllers/card_charges_controller.rb | 35 +++++++++++++ app/controllers/orders_controller.rb | 8 ++- app/helpers/card_charges_helper.rb | 2 + app/mailers/order_mailer.rb | 13 +++++ app/models/cart.rb | 4 ++ .../order_mailer/notify_order_placed.html.erb | 51 +++++++++++++++++++ .../orders/pay_with_credit_card.html.erb | 37 ++++++++++++++ config/environments/development.rb | 11 ++++ config/routes.rb | 1 + .../card_charges_controller_test.rb | 7 +++ test/helpers/card_charges_helper_test.rb | 4 ++ test/mailers/order_mailer_test.rb | 7 +++ test/mailers/previews/order_mailer_preview.rb | 4 ++ 19 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/card_charges.js.coffee create mode 100644 app/assets/stylesheets/card_charges.css.scss create mode 100644 app/controllers/card_charges_controller.rb create mode 100644 app/helpers/card_charges_helper.rb create mode 100644 app/mailers/order_mailer.rb create mode 100644 app/views/order_mailer/notify_order_placed.html.erb create mode 100644 app/views/orders/pay_with_credit_card.html.erb create mode 100644 test/controllers/card_charges_controller_test.rb create mode 100644 test/helpers/card_charges_helper_test.rb create mode 100644 test/mailers/order_mailer_test.rb create mode 100644 test/mailers/previews/order_mailer_preview.rb diff --git a/Gemfile b/Gemfile index a5f49ed2..07c05ccb 100644 --- a/Gemfile +++ b/Gemfile @@ -54,3 +54,10 @@ gem 'simple_form' #for state machines gem "aasm" + +group :development do + gem "letter_opener" + gem "roadie" +end + +gem "stripe" diff --git a/Gemfile.lock b/Gemfile.lock index 08e64a40..a30b0f32 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -34,6 +34,7 @@ GEM minitest (~> 5.1) thread_safe (~> 0.1) tzinfo (~> 1.1) + addressable (2.3.6) arel (5.0.1.20140414130214) bcrypt (3.1.7) bcrypt-ruby (3.1.5) @@ -53,6 +54,8 @@ GEM coffee-script-source execjs coffee-script-source (1.7.0) + css_parser (1.3.5) + addressable devise (3.1.0) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) @@ -70,14 +73,21 @@ GEM railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.1) + launchy (2.4.2) + addressable (~> 2.3) + letter_opener (1.2.0) + launchy (~> 2.2) mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.25.1) mini_magick (3.7.0) subexec (~> 0.2.1) + mini_portile (0.6.0) minitest (5.3.4) multi_json (1.10.1) + nokogiri (1.6.2.1) + mini_portile (= 0.6.0) orm_adapter (0.5.0) polyglot (0.3.5) rack (1.5.2) @@ -101,6 +111,13 @@ GEM rake (10.3.2) rdoc (4.1.1) json (~> 1.4) + rest-client (1.6.7) + mime-types (>= 1.16) + roadie (2.4.3) + actionmailer (> 3.0.0, < 5.0.0) + css_parser (~> 1.3.4) + nokogiri (> 1.5.0) + sprockets sass (3.2.19) sass-rails (4.0.3) railties (>= 4.0.0, < 5.0) @@ -122,6 +139,10 @@ GEM activesupport (>= 3.0) sprockets (~> 2.8) sqlite3 (1.3.9) + stripe (1.14.0) + json (~> 1.8.1) + mime-types (~> 1.25) + rest-client (~> 1.4) thor (0.19.1) thread_safe (0.3.4) tilt (1.4.1) @@ -149,13 +170,16 @@ DEPENDENCIES devise jbuilder (~> 2.0) jquery-rails + letter_opener mini_magick rails (= 4.1.0) + roadie sass-rails (~> 4.0.3) sdoc (~> 0.4.0) simple_form spring sqlite3 + stripe subexec! turbolinks uglifier (>= 1.3.0) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 77431764..021f6930 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,3 +15,4 @@ //= require turbolinks //= require_tree . //= require bootstrap +//= require orders diff --git a/app/assets/javascripts/card_charges.js.coffee b/app/assets/javascripts/card_charges.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/card_charges.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/orders.js.coffee b/app/assets/javascripts/orders.js.coffee index 24f83d18..86698481 100644 --- a/app/assets/javascripts/orders.js.coffee +++ b/app/assets/javascripts/orders.js.coffee @@ -1,3 +1,35 @@ # 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/ + +jQuery ($) -> + $("#payment-form").submit (event) -> + $form = $(this) + + # Disable the submit button to prevent repeated clicks + $form.find("button").prop "disabled", true + Stripe.createToken $form, stripeResponseHandler + + # Prevent the form from submitting with the default action + false + + return + +stripeResponseHandler = (status, response) -> + $form = $("#payment-form") + if response.error + + # Show the errors on the form + $form.find(".payment-errors").text response.error.message + $form.find("button").prop "disabled", false + else + + # token contains id, last4, and card type + token = response.id + + # Insert the token into the form so it gets submitted to the server + $form.append $("").val(token) + + # and submit + $form.get(0).submit() + return diff --git a/app/assets/stylesheets/card_charges.css.scss b/app/assets/stylesheets/card_charges.css.scss new file mode 100644 index 00000000..24adb84c --- /dev/null +++ b/app/assets/stylesheets/card_charges.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the card_charges controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/card_charges_controller.rb b/app/controllers/card_charges_controller.rb new file mode 100644 index 00000000..5633a35a --- /dev/null +++ b/app/controllers/card_charges_controller.rb @@ -0,0 +1,35 @@ +class CardChargesController < ApplicationController + + before_action :authenticate_user! + + def create + + @order = current_user.orders.find_by_token(params[:order_id]) + @amount = @order.total * 100 # in cents + + Stripe.api_key = 'sk_test_oRx3n1ew0kZIkY9hLvPMV8Dy' + + customer = Stripe::Customer.create( + :email => current_user.email, + :card => params[:stripeToken] + ) + + + charge = Stripe::Charge.create( + :customer => customer.id, + :amount => @amount, + :description => @order.token , + :currency => 'usd' + ) + + @order.set_payment_with!("credit_card") + @order.make_payment! + + redirect_to order_path(@order.token), :notice => "成功完成付款" + + rescue Stripe::CardError => e + flash[:error] = e.message + render "orders/pay_with_credit_card" + end + +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index ea1da121..85e84b62 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -12,6 +12,9 @@ def create if @order.save @order.build_item_cache_from_cart(current_cart) @order.calculate_total!(current_cart) + current_cart.clear! + OrderMailer.notify_order_placed(@order).deliver + redirect_to order_path(@order.token) else render "carts/index" @@ -20,11 +23,6 @@ def create def pay_with_credit_card @order = current_user.orders.find_by_token(params[:id]) - @order.set_payment_with!("credit_card") - @order.make_payment! - current_cart.destroy! - redirect_to account_orders_path :notice => "成功完成付款" - end private diff --git a/app/helpers/card_charges_helper.rb b/app/helpers/card_charges_helper.rb new file mode 100644 index 00000000..5c18c543 --- /dev/null +++ b/app/helpers/card_charges_helper.rb @@ -0,0 +1,2 @@ +module CardChargesHelper +end diff --git a/app/mailers/order_mailer.rb b/app/mailers/order_mailer.rb new file mode 100644 index 00000000..474260e3 --- /dev/null +++ b/app/mailers/order_mailer.rb @@ -0,0 +1,13 @@ +class OrderMailer < ActionMailer::Base + default from: "staff@artstore.com" + + def notify_order_placed(order) + @order = order + @user = order.user + @order_items = @order.items + @order_info = @order.info + + + mail(:to => @user.email , :subject => " [ArtStore] 感謝您完成本次的下單,以下是您這次購物明細 #{order.token}") + end +end diff --git a/app/models/cart.rb b/app/models/cart.rb index 3e7f1d98..0d63340c 100644 --- a/app/models/cart.rb +++ b/app/models/cart.rb @@ -6,4 +6,8 @@ class Cart < ActiveRecord::Base def total_price cart_items.inject(0) {|sum, item| sum + (item.product.price * item.quantity) } end + + def clear! + cart_items.delete_all + end end diff --git a/app/views/order_mailer/notify_order_placed.html.erb b/app/views/order_mailer/notify_order_placed.html.erb new file mode 100644 index 00000000..911a6c7a --- /dev/null +++ b/app/views/order_mailer/notify_order_placed.html.erb @@ -0,0 +1,51 @@ + +
    +
    +

    訂單明細

    + + + + + + + + + <% @order_items.each do |order_item| %> + + + + + <% end %> + +
    商品明細單價
    + <%= order_item.product_name %> + <%= order_item.price %>
    +
    + + 總計 <%= @order.total %> NTD + +
    +
    +

    寄送資訊

    + + + + + + + + + + + + + + + +
    訂購人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    收貨人
    + <%= @order_info.billing_name %> - <%= @order_info.billing_address %> +
    +
    +
    diff --git a/app/views/orders/pay_with_credit_card.html.erb b/app/views/orders/pay_with_credit_card.html.erb new file mode 100644 index 00000000..195efb23 --- /dev/null +++ b/app/views/orders/pay_with_credit_card.html.erb @@ -0,0 +1,37 @@ + + +<%= form_tag order_card_charges_path(@order.token), :id => "payment-form", :class => "form form-horizontal" do %> + +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +<% end %> +
    diff --git a/config/environments/development.rb b/config/environments/development.rb index ddf0e90c..a6d802b8 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -16,6 +16,17 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + #config.action_mailer.delivery_method = :letter_opener + config.action_mailer.smtp_settings = { + :port => 587, + :address => "smtp.mailgun.org", + :user_name => "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + :password => "9dtq9y2j4n23", + :domain => "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + :authentication => :plain + } + config.action_mailer.delivery_method = :smtp + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/config/routes.rb b/config/routes.rb index 35f957d3..41f2cddc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,7 @@ member do get :pay_with_credit_card end + resources :card_charges end namespace :account do diff --git a/test/controllers/card_charges_controller_test.rb b/test/controllers/card_charges_controller_test.rb new file mode 100644 index 00000000..c5002f27 --- /dev/null +++ b/test/controllers/card_charges_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CardChargesControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/helpers/card_charges_helper_test.rb b/test/helpers/card_charges_helper_test.rb new file mode 100644 index 00000000..1fe502e7 --- /dev/null +++ b/test/helpers/card_charges_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class CardChargesHelperTest < ActionView::TestCase +end diff --git a/test/mailers/order_mailer_test.rb b/test/mailers/order_mailer_test.rb new file mode 100644 index 00000000..6e2129de --- /dev/null +++ b/test/mailers/order_mailer_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class OrderMailerTest < ActionMailer::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/mailers/previews/order_mailer_preview.rb b/test/mailers/previews/order_mailer_preview.rb new file mode 100644 index 00000000..7be457e2 --- /dev/null +++ b/test/mailers/previews/order_mailer_preview.rb @@ -0,0 +1,4 @@ +# Preview all emails at http://localhost:3000/rails/mailers/order_mailer +class OrderMailerPreview < ActionMailer::Preview + +end From e814cfa9c0df774da2a30328e8684b3e641104b5 Mon Sep 17 00:00:00 2001 From: orga Date: Tue, 24 Jun 2014 22:50:49 +0800 Subject: [PATCH 52/59] extract class: order_placing_service --- app/controllers/orders_controller.rb | 6 +----- app/services/order_placing_service.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 app/services/order_placing_service.rb diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 85e84b62..1dae6ed2 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -10,11 +10,7 @@ def create @order = current_user.orders.build(order_params) if @order.save - @order.build_item_cache_from_cart(current_cart) - @order.calculate_total!(current_cart) - current_cart.clear! - OrderMailer.notify_order_placed(@order).deliver - + OrderPlacingService.new(current_cart, @order).place_order! redirect_to order_path(@order.token) else render "carts/index" diff --git a/app/services/order_placing_service.rb b/app/services/order_placing_service.rb new file mode 100644 index 00000000..ff06bf7b --- /dev/null +++ b/app/services/order_placing_service.rb @@ -0,0 +1,14 @@ +class OrderPlacingService + + def initialize(cart, order) + @cart = cart + @order = order + end + + def place_order! + @order.build_item_cache_from_cart(@cart) + @order.calculate_total!(@cart) + @cart.clear! + OrderMailer.notify_order_placed(@order).deliver + end +end From 39eff217728072da2397ea8c341585bc1cc8f640 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 25 Jun 2014 00:18:33 +0800 Subject: [PATCH 53/59] 1. send email after card paid 2. fix bug if product quantity is 0, add to cart will error --- TODO | 2 +- app/controllers/card_charges_controller.rb | 3 ++- app/mailers/order_mailer.rb | 7 ++++++ app/models/cart_item.rb | 4 ++-- .../order_mailer/notify_card_paid.html.erb | 3 +++ config/environments/development.rb | 22 +++++++++---------- 6 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 app/views/order_mailer/notify_card_paid.html.erb diff --git a/TODO b/TODO index acde63da..210435a9 100644 --- a/TODO +++ b/TODO @@ -42,7 +42,7 @@ ✔ ⾝為消費者,當系統生成一張訂單前,我可以填寫寄送資訊 @done(2014-06-16 09:58) @project(購物) ✔ 身為消費者,當系統⽣生成⼀張訂單後,我可以用信用卡結帳 @done(2014-06-16 09:58) @project(購物) ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 - ☐ 信用卡付款成功後也要收到通知信 + ✔ 信用卡付款成功後也要收到通知信 @done(2014-06-25 12:18) @project(購物) ☐ 身為消費者, 可以從信中連結到訂單網頁 ✔ 身為消費者,當訂單成立後,購物車需要清空 @done(2014-06-18 10:21) @project(購物) ✔ 身為消費者,需要在訂單頁面看到正確的商品數量 @done(2014-06-18 10:21) @project(購物) diff --git a/app/controllers/card_charges_controller.rb b/app/controllers/card_charges_controller.rb index 5633a35a..5407b398 100644 --- a/app/controllers/card_charges_controller.rb +++ b/app/controllers/card_charges_controller.rb @@ -24,7 +24,8 @@ def create @order.set_payment_with!("credit_card") @order.make_payment! - + OrderMailer.notify_card_paid(@order).deliver + redirect_to order_path(@order.token), :notice => "成功完成付款" rescue Stripe::CardError => e diff --git a/app/mailers/order_mailer.rb b/app/mailers/order_mailer.rb index 474260e3..c1268a7e 100644 --- a/app/mailers/order_mailer.rb +++ b/app/mailers/order_mailer.rb @@ -10,4 +10,11 @@ def notify_order_placed(order) mail(:to => @user.email , :subject => " [ArtStore] 感謝您完成本次的下單,以下是您這次購物明細 #{order.token}") end + + def notify_card_paid(order) + @order = order + @user = order.user + + mail(:to => @user.email , :subject => " [ArtStore] 完成付款通知 #{order.token}") + end end diff --git a/app/models/cart_item.rb b/app/models/cart_item.rb index 1520699a..2744c44a 100644 --- a/app/models/cart_item.rb +++ b/app/models/cart_item.rb @@ -7,8 +7,8 @@ class CartItem < ActiveRecord::Base private def check_product_quantity - - if product.quantity < quantity + + if quantity == nil || product.quantity < quantity errors.add(:quantity, "You order too many") end end diff --git a/app/views/order_mailer/notify_card_paid.html.erb b/app/views/order_mailer/notify_card_paid.html.erb new file mode 100644 index 00000000..55a94715 --- /dev/null +++ b/app/views/order_mailer/notify_card_paid.html.erb @@ -0,0 +1,3 @@ + +

    您的消費總額<%= @order.total %>已完成付款

    +
    diff --git a/config/environments/development.rb b/config/environments/development.rb index a6d802b8..7b2edf2e 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -16,17 +16,17 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - #config.action_mailer.delivery_method = :letter_opener - config.action_mailer.smtp_settings = { - :port => 587, - :address => "smtp.mailgun.org", - :user_name => "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", - :password => "9dtq9y2j4n23", - :domain => "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", - :authentication => :plain - } - config.action_mailer.delivery_method = :smtp - + config.action_mailer.delivery_method = :letter_opener + #config.action_mailer.smtp_settings = { + # :port => 587, + # :address => "smtp.mailgun.org", + # :user_name => "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + # :password => "9dtq9y2j4n23", + # :domain => "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + # :authentication => :plain + #} + #config.action_mailer.delivery_method = :smtp + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log From ed20820474a898966896daf401390cf73b3d5875 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 25 Jun 2014 00:36:29 +0800 Subject: [PATCH 54/59] add order link into mail --- TODO | 2 +- .../order_mailer/notify_card_paid.html.erb | 1 + .../order_mailer/notify_order_placed.html.erb | 1 + config/environments/development.rb | 22 ++++++++++--------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/TODO b/TODO index 210435a9..ae3420cb 100644 --- a/TODO +++ b/TODO @@ -43,7 +43,7 @@ ✔ 身為消費者,當系統⽣生成⼀張訂單後,我可以用信用卡結帳 @done(2014-06-16 09:58) @project(購物) ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 ✔ 信用卡付款成功後也要收到通知信 @done(2014-06-25 12:18) @project(購物) - ☐ 身為消費者, 可以從信中連結到訂單網頁 + ✔ 身為消費者, 可以從信中連結到訂單網頁 @done(2014-06-25 12:35) @project(購物) ✔ 身為消費者,當訂單成立後,購物車需要清空 @done(2014-06-18 10:21) @project(購物) ✔ 身為消費者,需要在訂單頁面看到正確的商品數量 @done(2014-06-18 10:21) @project(購物) ☐ 美化訂單畫面 diff --git a/app/views/order_mailer/notify_card_paid.html.erb b/app/views/order_mailer/notify_card_paid.html.erb index 55a94715..79876e15 100644 --- a/app/views/order_mailer/notify_card_paid.html.erb +++ b/app/views/order_mailer/notify_card_paid.html.erb @@ -1,3 +1,4 @@

    您的消費總額<%= @order.total %>已完成付款

    + <%= link_to("訂單連結", order_url(@order.token)) %>
    diff --git a/app/views/order_mailer/notify_order_placed.html.erb b/app/views/order_mailer/notify_order_placed.html.erb index 911a6c7a..b4c490bd 100644 --- a/app/views/order_mailer/notify_order_placed.html.erb +++ b/app/views/order_mailer/notify_order_placed.html.erb @@ -47,5 +47,6 @@ + <%= link_to("訂單連結", order_url(@order.token)) %>
    diff --git a/config/environments/development.rb b/config/environments/development.rb index 7b2edf2e..2ffebdc7 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -16,16 +16,16 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - config.action_mailer.delivery_method = :letter_opener - #config.action_mailer.smtp_settings = { - # :port => 587, - # :address => "smtp.mailgun.org", - # :user_name => "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", - # :password => "9dtq9y2j4n23", - # :domain => "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", - # :authentication => :plain - #} - #config.action_mailer.delivery_method = :smtp + #config.action_mailer.delivery_method = :letter_opener + config.action_mailer.smtp_settings = { + :port => 587, + :address => "smtp.mailgun.org", + :user_name => "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + :password => "9dtq9y2j4n23", + :domain => "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + :authentication => :plain + } + config.action_mailer.delivery_method = :smtp # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log @@ -45,4 +45,6 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + config.action_mailer.default_url_options = { :host => "localhost:3000" } end From b9ea1a3fbe6f6591fbd7014f81b1f4c5c3d87d82 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 25 Jun 2014 22:00:03 +0800 Subject: [PATCH 55/59] add settingslogic for moving stripe key to yml file --- Gemfile | 5 +++++ Gemfile.lock | 2 ++ TODO | 2 ++ app/controllers/card_charges_controller.rb | 4 ++-- app/models/setting.rb | 5 +++++ app/views/orders/pay_with_credit_card.html.erb | 2 +- config/config.yml | 13 +++++++++++++ 7 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 app/models/setting.rb create mode 100644 config/config.yml diff --git a/Gemfile b/Gemfile index 07c05ccb..94d3a1ef 100644 --- a/Gemfile +++ b/Gemfile @@ -55,9 +55,14 @@ gem 'simple_form' #for state machines gem "aasm" +#for dispaly email at local group :development do gem "letter_opener" gem "roadie" end +#for credit card payment gem "stripe" + +#for store secure key info +gem "settingslogic" diff --git a/Gemfile.lock b/Gemfile.lock index a30b0f32..1135afce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -127,6 +127,7 @@ GEM sdoc (0.4.0) json (~> 1.8) rdoc (~> 4.0, < 5.0) + settingslogic (2.0.9) simple_form (1.4.1) spring (1.1.3) sprockets (2.11.0) @@ -176,6 +177,7 @@ DEPENDENCIES roadie sass-rails (~> 4.0.3) sdoc (~> 0.4.0) + settingslogic simple_form spring sqlite3 diff --git a/TODO b/TODO index ae3420cb..caf4e14e 100644 --- a/TODO +++ b/TODO @@ -43,6 +43,8 @@ ✔ 身為消費者,當系統⽣生成⼀張訂單後,我可以用信用卡結帳 @done(2014-06-16 09:58) @project(購物) ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 ✔ 信用卡付款成功後也要收到通知信 @done(2014-06-25 12:18) @project(購物) + ☐ 將通知信用的key放入SettingLogic提供的yml內 + ✔ 將信用卡繳費用的key放入SettingLogic提供的yml內 @done(2014-06-25 09:58) @project(購物) ✔ 身為消費者, 可以從信中連結到訂單網頁 @done(2014-06-25 12:35) @project(購物) ✔ 身為消費者,當訂單成立後,購物車需要清空 @done(2014-06-18 10:21) @project(購物) ✔ 身為消費者,需要在訂單頁面看到正確的商品數量 @done(2014-06-18 10:21) @project(購物) diff --git a/app/controllers/card_charges_controller.rb b/app/controllers/card_charges_controller.rb index 5407b398..433c58ea 100644 --- a/app/controllers/card_charges_controller.rb +++ b/app/controllers/card_charges_controller.rb @@ -7,7 +7,7 @@ def create @order = current_user.orders.find_by_token(params[:order_id]) @amount = @order.total * 100 # in cents - Stripe.api_key = 'sk_test_oRx3n1ew0kZIkY9hLvPMV8Dy' + Stripe.api_key = Setting.stripe.api_key customer = Stripe::Customer.create( :email => current_user.email, @@ -25,7 +25,7 @@ def create @order.set_payment_with!("credit_card") @order.make_payment! OrderMailer.notify_card_paid(@order).deliver - + redirect_to order_path(@order.token), :notice => "成功完成付款" rescue Stripe::CardError => e diff --git a/app/models/setting.rb b/app/models/setting.rb new file mode 100644 index 00000000..9460739d --- /dev/null +++ b/app/models/setting.rb @@ -0,0 +1,5 @@ +# -*- encoding : utf-8 -*- +class Setting < Settingslogic + source "#{Rails.root}/config/config.yml" + namespace Rails.env +end diff --git a/app/views/orders/pay_with_credit_card.html.erb b/app/views/orders/pay_with_credit_card.html.erb index 195efb23..89a69828 100644 --- a/app/views/orders/pay_with_credit_card.html.erb +++ b/app/views/orders/pay_with_credit_card.html.erb @@ -1,6 +1,6 @@ <%= form_tag order_card_charges_path(@order.token), :id => "payment-form", :class => "form form-horizontal" do %> diff --git a/config/config.yml b/config/config.yml new file mode 100644 index 00000000..e9858507 --- /dev/null +++ b/config/config.yml @@ -0,0 +1,13 @@ +defaults: &defaults + stripe: + api_key: 'sk_test_oRx3n1ew0kZIkY9hLvPMV8Dy' + public_key: 'pk_test_jS6BKf6bMnfVZ9BiaUf533kd' + +development: + <<: *defaults + +test: + <<: *defaults + +production: + <<: *defaults From 5571d15ab3f658bfe1bdb8c3347601865d68d007 Mon Sep 17 00:00:00 2001 From: orga Date: Wed, 25 Jun 2014 23:30:33 +0800 Subject: [PATCH 56/59] move email key to yml file --- TODO | 2 +- config/config.yml | 4 ++++ config/environments/development.rb | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index caf4e14e..bc5c78e6 100644 --- a/TODO +++ b/TODO @@ -43,7 +43,7 @@ ✔ 身為消費者,當系統⽣生成⼀張訂單後,我可以用信用卡結帳 @done(2014-06-16 09:58) @project(購物) ☐ ⾝為消費者,當我用信用卡結帳後,我的信箱要能收到一張訂單確認信 ✔ 信用卡付款成功後也要收到通知信 @done(2014-06-25 12:18) @project(購物) - ☐ 將通知信用的key放入SettingLogic提供的yml內 + ✔ 將通知信用的key放入SettingLogic提供的yml內 @done(2014-06-25 11:30) @project(購物) ✔ 將信用卡繳費用的key放入SettingLogic提供的yml內 @done(2014-06-25 09:58) @project(購物) ✔ 身為消費者, 可以從信中連結到訂單網頁 @done(2014-06-25 12:35) @project(購物) ✔ 身為消費者,當訂單成立後,購物車需要清空 @done(2014-06-18 10:21) @project(購物) diff --git a/config/config.yml b/config/config.yml index e9858507..87e93275 100644 --- a/config/config.yml +++ b/config/config.yml @@ -1,4 +1,8 @@ defaults: &defaults + mail: + user_name: "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org" + password: "9dtq9y2j4n23" + domain: "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org" stripe: api_key: 'sk_test_oRx3n1ew0kZIkY9hLvPMV8Dy' public_key: 'pk_test_jS6BKf6bMnfVZ9BiaUf533kd' diff --git a/config/environments/development.rb b/config/environments/development.rb index 2ffebdc7..f2a1ef8c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -20,9 +20,9 @@ config.action_mailer.smtp_settings = { :port => 587, :address => "smtp.mailgun.org", - :user_name => "postmaster@sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", - :password => "9dtq9y2j4n23", - :domain => "sandboxc429a9c3e2a6491da69d4593dc8fcf34.mailgun.org", + :user_name => Setting.mail.user_name, + :password => Setting.mail.password, + :domain => Setting.mail.domain, :authentication => :plain } config.action_mailer.delivery_method = :smtp From 31c0fdc304be7c8164ff3cfeb5c0625132e1b909 Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 26 Jun 2014 21:58:42 +0800 Subject: [PATCH 57/59] extract class from card_charges_controller --- TODO | 1 + app/controllers/card_charges_controller.rb | 36 ++++++---------------- app/services/credit_card_service.rb | 25 +++++++++++++++ 3 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 app/services/credit_card_service.rb diff --git a/TODO b/TODO index bc5c78e6..9d4ec54f 100644 --- a/TODO +++ b/TODO @@ -66,3 +66,4 @@ ✔ 將application.html中的nav bar和error message 用partial抽出 @done(2014-06-14 12:29) @project(Refactoring) ✔ 簡化admin/order#show狀態轉換的code, 包含viwe, controller @done(2014-06-20 02:44) @project(重構) ✔ 將加入/移除購物車功能, 轉移到cart_items controller相對應的create/destroy action @done(2014-06-22 10:58) @project(重構) + ✔ 將card_charges controller內過多的程式碼移出. @done(2014-06-26 09:57) @project(重構) diff --git a/app/controllers/card_charges_controller.rb b/app/controllers/card_charges_controller.rb index 433c58ea..67cd3d9f 100644 --- a/app/controllers/card_charges_controller.rb +++ b/app/controllers/card_charges_controller.rb @@ -4,33 +4,17 @@ class CardChargesController < ApplicationController def create + error = CreditCardService.charge(current_user, params) @order = current_user.orders.find_by_token(params[:order_id]) - @amount = @order.total * 100 # in cents - - Stripe.api_key = Setting.stripe.api_key - - customer = Stripe::Customer.create( - :email => current_user.email, - :card => params[:stripeToken] - ) - - - charge = Stripe::Charge.create( - :customer => customer.id, - :amount => @amount, - :description => @order.token , - :currency => 'usd' - ) - - @order.set_payment_with!("credit_card") - @order.make_payment! - OrderMailer.notify_card_paid(@order).deliver - - redirect_to order_path(@order.token), :notice => "成功完成付款" - - rescue Stripe::CardError => e - flash[:error] = e.message + if error + flash[:error] = error render "orders/pay_with_credit_card" - end + else + @order.set_payment_with!("credit_card") + @order.make_payment! + OrderMailer.notify_card_paid(@order).deliver + redirect_to order_path(@order.token), :notice => "成功完成付款" + end + end end diff --git a/app/services/credit_card_service.rb b/app/services/credit_card_service.rb new file mode 100644 index 00000000..554940e9 --- /dev/null +++ b/app/services/credit_card_service.rb @@ -0,0 +1,25 @@ +class CreditCardService + def self.charge(current_user, params) + @order = current_user.orders.find_by_token(params[:order_id]) + @amount = @order.total * 100 # in cents + + Stripe.api_key = Setting.stripe.api_key + + customer = Stripe::Customer.create( + :email => current_user.email, + :card => params[:stripeToken] + ) + + + charge = Stripe::Charge.create( + :customer => customer.id, + :amount => @amount, + :description => @order.token , + :currency => 'usd' + ) + + nil + rescue Stripe::CardError => e + e.message + end +end From 362a374d8c01a4cd1eb866840f609942fc1373c3 Mon Sep 17 00:00:00 2001 From: orga Date: Thu, 26 Jun 2014 23:41:16 +0800 Subject: [PATCH 58/59] add search product feature (ransack) --- Gemfile | 5 ++- Gemfile.lock | 9 ++++ TODO | 1 + app/controllers/products_controller.rb | 16 ++----- app/views/products/index.html.erb | 61 +++++++++++++++++++------- config/application.rb | 2 +- config/locales/zh-TW.yml | 9 ++++ config/routes.rb | 7 +-- 8 files changed, 72 insertions(+), 38 deletions(-) create mode 100644 config/locales/zh-TW.yml diff --git a/Gemfile b/Gemfile index 94d3a1ef..78623d87 100644 --- a/Gemfile +++ b/Gemfile @@ -55,7 +55,7 @@ gem 'simple_form' #for state machines gem "aasm" -#for dispaly email at local +#for dispaly email at local group :development do gem "letter_opener" gem "roadie" @@ -66,3 +66,6 @@ gem "stripe" #for store secure key info gem "settingslogic" + +#for search product +gem "ransack" diff --git a/Gemfile.lock b/Gemfile.lock index 1135afce..5e4a7ff1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,6 +89,8 @@ GEM nokogiri (1.6.2.1) mini_portile (= 0.6.0) orm_adapter (0.5.0) + polyamorous (1.0.0) + activerecord (>= 3.0) polyglot (0.3.5) rack (1.5.2) rack-test (0.6.2) @@ -109,6 +111,12 @@ GEM rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rake (10.3.2) + ransack (1.2.3) + actionpack (>= 3.0) + activerecord (>= 3.0) + activesupport (>= 3.0) + i18n + polyamorous (~> 1.0.0) rdoc (4.1.1) json (~> 1.4) rest-client (1.6.7) @@ -174,6 +182,7 @@ DEPENDENCIES letter_opener mini_magick rails (= 4.1.0) + ransack roadie sass-rails (~> 4.0.3) sdoc (~> 0.4.0) diff --git a/TODO b/TODO index 9d4ec54f..eeb0a1ad 100644 --- a/TODO +++ b/TODO @@ -55,6 +55,7 @@ ✔ 身為消費者, 不能將數量為0的商品加入購物車 @done(2014-06-18 09:50) @project(購物) ✔ 身為消費者, 能在account/orders看到過去的訂單記錄 @done(2014-06-18 10:45) @project(購物) ✔ 身為消費者, 能夠在結賬後自動跳轉到account/orders#index @done(2014-06-18 10:51) @project(購物) + ✔ 身為消費者, 能夠搜尋標題及價格範圍找到想要的產品 @done(2014-06-26 11:40) @project(購物) 系統訊息: diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 0c2569d9..8f1a9898 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -1,6 +1,8 @@ class ProductsController < ApplicationController + def index - @products = Product.all + @q = Product.search(params[:q]) + @products = @q.result(distinct: true) end def show @@ -8,16 +10,4 @@ def show @cart_item = current_cart.cart_items.build(quantity: 1) end - def del_from_cart - @product = Product.find(params[:id]) - if current_cart.items.include?(@product) - current_cart.del_product_from_cart(@product) - flash[:notice] = "你已成功將 #{@product.title} 移除" - else - flash[:warning] = "你的購物車沒有此物品" - end - - redirect_to carts_path - end - end diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb index ccd2d149..c60bd134 100644 --- a/app/views/products/index.html.erb +++ b/app/views/products/index.html.erb @@ -1,20 +1,47 @@
    - - - - - - - - - <% @products.each do |product| %> - - - - +
    +
    + <%= search_form_for @q do |f| %> +
    + <%= f.label :title_cont, class: "control-label" %> + <%= f.search_field :title_cont, class: "form-control" %> +
    +
    + <%= f.label :price_in, class: "control-label" %> +
    +
    + <%= f.search_field :price_gteq, class: "form-control" %> +
    +
    +

    ~

    +
    +
    + <%= f.search_field :price_lteq, class: "form-control" %> +
    +
    +
    + <%= f.submit class: "btn btn-primary pull-right"%> <% end %> -
    -
    產品連結
    <%= product.title %> - <%= link_to('Show', product_path(product), :class => "btn btn-info") %> -
    +
    +
    + + + + + + + + + <% @products.each do |product| %> + + + + + <% end %> + +
    產品連結
    <%= product.title %> + <%= link_to('Show', product_path(product), :class => "btn btn-info") %> +
    +
    +
    diff --git a/config/application.rb b/config/application.rb index d21f3302..44592989 100644 --- a/config/application.rb +++ b/config/application.rb @@ -18,6 +18,6 @@ class Application < Rails::Application # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - # config.i18n.default_locale = :de + config.i18n.default_locale = "zh-TW" end end diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml new file mode 100644 index 00000000..3811beed --- /dev/null +++ b/config/locales/zh-TW.yml @@ -0,0 +1,9 @@ +zh-TW: + ransack: + predicates: + cont: "包含" + in: "範圍" + attributes: + product: + title: "標題" + price: "價格" diff --git a/config/routes.rb b/config/routes.rb index 41f2cddc..2dd75897 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,12 +14,7 @@ end end - resources :products do - member do - post :add_to_cart - post :del_from_cart - end - end + resources :products resources :carts do member do From 8dfff46fc15c5d779a1c14f4d7f59a84f58cd1bb Mon Sep 17 00:00:00 2001 From: orga Date: Fri, 27 Jun 2014 21:56:43 +0800 Subject: [PATCH 59/59] 1. update simple_form. 2. add devise zh-TW --- Gemfile.lock | 22 +-- config/initializers/simple_form.rb | 146 +++++++++++++------ config/initializers/simple_form_bootstrap.rb | 45 ++++++ config/locales/devise.zh-TW.yml | 57 ++++++++ config/locales/simple_form.en.yml | 12 +- lib/templates/erb/scaffold/_form.html.erb | 4 +- 6 files changed, 221 insertions(+), 65 deletions(-) create mode 100644 config/initializers/simple_form_bootstrap.rb create mode 100644 config/locales/devise.zh-TW.yml diff --git a/Gemfile.lock b/Gemfile.lock index 5e4a7ff1..6d9dcfde 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -37,9 +37,7 @@ GEM addressable (2.3.6) arel (5.0.1.20140414130214) bcrypt (3.1.7) - bcrypt-ruby (3.1.5) - bcrypt (>= 3.1.3) - bootstrap-sass (3.1.1.1) + bootstrap-sass (3.2.0.0) sass (~> 3.2) builder (3.2.2) carrierwave (0.10.0) @@ -56,20 +54,20 @@ GEM coffee-script-source (1.7.0) css_parser (1.3.5) addressable - devise (3.1.0) - bcrypt-ruby (~> 3.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) erubis (2.7.0) - execjs (2.2.0) + execjs (2.2.1) hike (1.2.3) i18n (0.6.9) - jbuilder (2.0.8) + jbuilder (2.1.1) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) - jquery-rails (3.1.0) + jquery-rails (3.1.1) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.1) @@ -84,7 +82,7 @@ GEM mini_magick (3.7.0) subexec (~> 0.2.1) mini_portile (0.6.0) - minitest (5.3.4) + minitest (5.3.5) multi_json (1.10.1) nokogiri (1.6.2.1) mini_portile (= 0.6.0) @@ -136,7 +134,9 @@ GEM json (~> 1.8) rdoc (~> 4.0, < 5.0) settingslogic (2.0.9) - simple_form (1.4.1) + simple_form (3.0.2) + actionpack (~> 4.0) + activemodel (~> 4.0) spring (1.1.3) sprockets (2.11.0) hike (~> 1.2) @@ -162,7 +162,7 @@ GEM coffee-rails tzinfo (1.2.1) thread_safe (~> 0.1) - uglifier (2.5.0) + uglifier (2.5.1) execjs (>= 0.3.0) json (>= 1.8.0) warden (1.2.3) diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb index 553961ba..6986de98 100644 --- a/config/initializers/simple_form.rb +++ b/config/initializers/simple_form.rb @@ -1,83 +1,129 @@ # Use this setup block to configure all options available in SimpleForm. SimpleForm.setup do |config| - # Components used by the form builder to generate a complete input. You can remove - # any of them, change the order, or even add your own components to the stack. - # config.components = [ :placeholder, :label_input, :hint, :error ] - - # Default tag used on hints. - # config.hint_tag = :span - - # CSS class to add to all hint tags. - # config.hint_class = :hint - - # CSS class used on errors. - # config.error_class = :error - - # Default tag used on errors. - # config.error_tag = :span - - # Method used to tidy up errors. + # Wrappers are used by the form builder to generate a + # complete input. You can remove any component from the + # wrapper, change the order or even add your own to the + # stack. The options given below are used to wrap the + # whole input. + config.wrappers :default, class: :input, + hint_class: :field_with_hint, error_class: :field_with_errors do |b| + ## Extensions enabled by default + # Any of these extensions can be disabled for a + # given input by passing: `f.input EXTENSION_NAME => false`. + # You can make any of these extensions optional by + # renaming `b.use` to `b.optional`. + + # Determines whether to use HTML5 (:email, :url, ...) + # and required attributes + b.use :html5 + + # Calculates placeholders automatically from I18n + # You can also pass a string as f.input placeholder: "Placeholder" + b.use :placeholder + + ## Optional extensions + # They are disabled unless you pass `f.input EXTENSION_NAME => :lookup` + # to the input. If so, they will retrieve the values from the model + # if any exists. If you want to enable the lookup for any of those + # extensions by default, you can change `b.optional` to `b.use`. + + # Calculates maxlength from length validations for string inputs + b.optional :maxlength + + # Calculates pattern from format validations for string inputs + b.optional :pattern + + # Calculates min and max from length validations for numeric inputs + b.optional :min_max + + # Calculates readonly automatically from readonly attributes + b.optional :readonly + + ## Inputs + b.use :label_input + b.use :hint, wrap_with: { tag: :span, class: :hint } + b.use :error, wrap_with: { tag: :span, class: :error } + end + + # The default wrapper to be used by the FormBuilder. + config.default_wrapper = :default + + # Define the way to render check boxes / radio buttons with labels. + # Defaults to :nested for bootstrap config. + # inline: input + label + # nested: label > input + config.boolean_style = :nested + + # Default class for buttons + config.button_class = 'btn' + + # Method used to tidy up errors. Specify any Rails Array method. + # :first lists the first message for each field. + # Use :to_sentence to list all errors for each field. # config.error_method = :first # Default tag used for error notification helper. - # config.error_notification_tag = :p + config.error_notification_tag = :div # CSS class to add for error notification helper. - # config.error_notification_class = :error_notification + config.error_notification_class = 'alert alert-error' # ID to add for error notification helper. # config.error_notification_id = nil - # You can wrap all inputs in a pre-defined tag. - # config.wrapper_tag = :div - - # CSS class to add to all wrapper tags. - # config.wrapper_class = :input + # Series of attempts to detect a default label method for collection. + # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] - # CSS class to add to the wrapper if the field has errors. - # config.wrapper_error_class = :field_with_errors + # Series of attempts to detect a default value method for collection. + # config.collection_value_methods = [ :id, :to_s ] # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. # config.collection_wrapper_tag = nil - # You can wrap each item in a collection of radio/check boxes with a tag, defaulting to span. - # config.item_wrapper_tag = :span + # You can define the class to use on all collection wrappers. Defaulting to none. + # config.collection_wrapper_class = nil - # Series of attempts to detect a default label method for collection. - # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] + # You can wrap each item in a collection of radio/check boxes with a tag, + # defaulting to :span. Please note that when using :boolean_style = :nested, + # SimpleForm will force this option to be a label. + # config.item_wrapper_tag = :span - # Series of attempts to detect a default value method for collection. - # config.collection_value_methods = [ :id, :to_s ] + # You can define a class to use in all item wrappers. Defaulting to none. + # config.item_wrapper_class = nil # How the label text should be generated altogether with the required text. # config.label_text = lambda { |label, required| "#{required} #{label}" } # You can define the class to use on all labels. Default is nil. - # config.label_class = nil + config.label_class = 'control-label' # You can define the class to use on all forms. Default is simple_form. # config.form_class = :simple_form + # You can define which elements should obtain additional classes + # config.generate_additional_classes_for = [:wrapper, :label, :input] + # Whether attributes are required by default (or not). Default is true. # config.required_by_default = true - # Tell browsers whether to use default HTML5 validations (novalidate option). - # Default is enabled. - # config.browser_validations = true + # Tell browsers whether to use the native HTML5 validations (novalidate form option). + # These validations are enabled in SimpleForm's internal config but disabled by default + # in this configuration, which is recommended due to some quirks from different browsers. + # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, + # change this configuration to true. + config.browser_validations = false - # Determines whether HTML5 types (:email, :url, :search, :tel) and attributes - # (e.g. required) are used or not. True by default. - # Having this on in non-HTML5 compliant sites can cause odd behavior in - # HTML5-aware browsers such as Chrome. - # config.html5 = true + # Collection of methods to detect if a file type was given. + # config.file_methods = [ :mounted_as, :file?, :public_filename ] # Custom mappings for input types. This should be a hash containing a regexp # to match as key, and the input type that will be used when the field name # matches the regexp as value. # config.input_mappings = { /count/ => :integer } - # Collection of methods to detect if a file type was given. - # config.file_methods = [ :mounted_as, :file?, :public_filename ] + # Custom wrappers for input types. This should be a hash containing an input + # type as key and the wrapper that will be used for all inputs with specified type. + # config.wrapper_mappings = { string: :prepend } # Default priority for time_zone inputs. # config.time_zone_priority = nil @@ -85,9 +131,15 @@ # Default priority for country inputs. # config.country_priority = nil - # Default size for text inputs. - # config.default_input_size = 50 + # When false, do not use translations for labels. + # config.translate_labels = true + + # Automatically discover new inputs in Rails' autoload path. + # config.inputs_discovery = true + + # Cache SimpleForm inputs discovery + # config.cache_discovery = !Rails.env.development? - # When false, do not use translations for labels, hints or placeholders. - # config.translate = true + # Default class for inputs + # config.input_class = nil end diff --git a/config/initializers/simple_form_bootstrap.rb b/config/initializers/simple_form_bootstrap.rb new file mode 100644 index 00000000..ad4ca74c --- /dev/null +++ b/config/initializers/simple_form_bootstrap.rb @@ -0,0 +1,45 @@ +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| + config.wrappers :bootstrap, tag: 'div', class: 'control-group', error_class: 'error' do |b| + b.use :html5 + b.use :placeholder + b.use :label + b.wrapper tag: 'div', class: 'controls' do |ba| + ba.use :input + ba.use :error, wrap_with: { tag: 'span', class: 'help-inline' } + ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } + end + end + + config.wrappers :prepend, tag: 'div', class: "control-group", error_class: 'error' do |b| + b.use :html5 + b.use :placeholder + b.use :label + b.wrapper tag: 'div', class: 'controls' do |input| + input.wrapper tag: 'div', class: 'input-prepend' do |prepend| + prepend.use :input + end + input.use :hint, wrap_with: { tag: 'span', class: 'help-block' } + input.use :error, wrap_with: { tag: 'span', class: 'help-inline' } + end + end + + config.wrappers :append, tag: 'div', class: "control-group", error_class: 'error' do |b| + b.use :html5 + b.use :placeholder + b.use :label + b.wrapper tag: 'div', class: 'controls' do |input| + input.wrapper tag: 'div', class: 'input-append' do |append| + append.use :input + end + input.use :hint, wrap_with: { tag: 'span', class: 'help-block' } + input.use :error, wrap_with: { tag: 'span', class: 'help-inline' } + end + end + + # Wrappers for forms and inputs using the Twitter Bootstrap toolkit. + # Check the Bootstrap docs (http://twitter.github.com/bootstrap) + # to learn about the different styles for forms and inputs, + # buttons and other elements. + config.default_wrapper = :bootstrap +end diff --git a/config/locales/devise.zh-TW.yml b/config/locales/devise.zh-TW.yml new file mode 100644 index 00000000..548a25c7 --- /dev/null +++ b/config/locales/devise.zh-TW.yml @@ -0,0 +1,57 @@ +zh-TW: + devise: + confirmations: + confirmed: 您的帳號已經通過確認。 + send_instructions: 您將在幾分鐘後收到一封電子郵件,內有確認帳號的步驟說明。 + send_paranoid_instructions: 如果此電子郵件信箱真存在於資料庫中的話,您將在幾分鐘後收到一封電子郵件, 說明確認帳號的手續。 + failure: + already_authenticated: 您已經登入。 + inactive: 您的帳號尚未被啟用。 + invalid: Email 或密碼是無效的。 + last_attempt: 帳號鎖定前的最後一次嘗試。 + locked: 您的帳號已被鎖定。 + not_found_in_database: Email 或密碼是無效的。 + timeout: 您的登入時效過期,請重新登入,才能繼續。 + unauthenticated: 您需要先註冊,登入後才能繼續。 + unconfirmed: 您的帳號需需要經過確認後,才能繼續。 + mailer: + confirmation_instructions: + subject: 確認步驟 + reset_password_instructions: + subject: 重設密碼步驟 + unlock_instructions: + subject: 解鎖步驟 + omniauth_callbacks: + failure: 因為「%{reason}」,無法認證您的 %{kind} 帳戶 + success: 已成功認證您的 %{kind} 帳戶 + passwords: + no_token: 您暫時不能訪問此頁面。您需要通過密碼重置郵件中的重置鏈接來訪問此頁面,如果您正是通過重置鏈接訪問,請確定鏈接的正確性。 + send_instructions: 您將在幾分鐘後收到一封電子郵件,內有重新設定密碼的步驟說明。 + send_paranoid_instructions: 如果此電子郵件信箱真存在於資料庫中的話,您將在幾分鐘後收到一封電子郵件,內有回復密碼專用的網址。 + updated: 您的密碼已被修改,而您現在已重新登入。 + updated_not_active: 您的密碼已被修改。 + registrations: + destroyed: 再會!您的帳號已被註銷。有緣再會。 + signed_up: 歡迎!您已經成功註冊。 + signed_up_but_inactive: 您已經成功註冊。但因帳號尚未啟用,目前暫時不能登入。 + signed_up_but_locked: 您已經成功註冊。可是,因為帳號被鎖住,目前暫時不能登入。 + signed_up_but_unconfirmed: 已傳送帳號確認信件至您的 Email 信箱,請收信、並點擊信中確認網址,以便啟用您的帳號。 + update_needs_confirmation: 您的帳號資料已成功更新,但您的新 Email 信箱需要再次被確認。請收信、並點擊信中確認用的網址,以便完成信箱確認手續。 + updated: 您已經成功的更新帳號資訊。 + sessions: + signed_in: 成功登入了。 + signed_out: 成功登出了。 + unlocks: + send_instructions: 您將在幾分鐘後收到一封電子郵件,內有將帳號解除鎖定的步驟說明。 + send_paranoid_instructions: 如果此帳號真的存在的話,您將在幾分鐘後收到一封電子郵件,內有將帳號解除鎖定的步驟說明。 + unlocked: 您的帳號已被解鎖,現在您已成功登入。 + errors: + messages: + already_confirmed: 已被確認過了,請試著登入看看 + confirmation_period_expired: 需要在%{period}以內確認,請再要一個新的。 + expired: 已經過期了,請再要一個新的 + not_found: 沒有找到 + not_locked: 沒有被鎖定 + not_saved: + one: 有一個錯誤導致%{resource}不能被儲存: + other: 有 %{count} 個錯誤導致%{resource}不能被儲存: diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 409e2651..0df11fe0 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -9,16 +9,18 @@ en: # When using html, text and mark won't be used. # html: '*' error_notification: - default_message: "Some errors were found, please take a look:" + default_message: "Please review the problems below:" # Labels and hints examples # labels: - # password: 'Password' + # defaults: + # password: 'Password' # user: # new: - # email: 'E-mail para efetuar o sign in.' + # email: 'E-mail to sign in.' # edit: # email: 'E-mail.' # hints: - # username: 'User name to sign in.' - # password: 'No special characters, please.' + # defaults: + # username: 'User name to sign in.' + # password: 'No special characters, please.' diff --git a/lib/templates/erb/scaffold/_form.html.erb b/lib/templates/erb/scaffold/_form.html.erb index 24a17689..201a069e 100644 --- a/lib/templates/erb/scaffold/_form.html.erb +++ b/lib/templates/erb/scaffold/_form.html.erb @@ -1,13 +1,13 @@ <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> <%%= f.error_notification %> -
    +
    <%- attributes.each do |attribute| -%> <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> <%- end -%>
    -
    +
    <%%= f.button :submit %>
    <%% end %>