From 53daffe99f50aa7f0a1c729fee43353d19da2443 Mon Sep 17 00:00:00 2001 From: BlackPearl96 Date: Mon, 19 Aug 2019 09:15:54 +0700 Subject: [PATCH] edit room --- Gemfile | 2 + Gemfile.lock | 25 ++++++-- app/assets/javascripts/manager/custom.js | 17 +++++ app/assets/stylesheets/manager/custom.scss | 64 +++++++++++++++++++ app/controllers/manager/rooms_controller.rb | 36 +++++++++-- app/models/room.rb | 4 +- app/models/room_image.rb | 8 +++ app/uploaders/image_uploader.rb | 49 ++++++++++++++ app/views/manager/rooms/_form.html.slim | 46 +++++++++++++ app/views/manager/rooms/_image.html.slim | 4 ++ app/views/manager/rooms/_room.html.slim | 10 +++ app/views/manager/rooms/edit.html.slim | 3 + app/views/manager/rooms/index.html.slim | 8 +++ app/views/manager/rooms/new.html.slim | 35 +--------- config/locales/en.yml | 25 +++++++- db/migrate/20190816042328_create_rooms.rb | 2 +- .../20190823063416_create_room_images.rb | 10 +++ ...e_active_storage_tables.active_storage.rb} | 0 db/schema.rb | 32 +++++++++- 19 files changed, 331 insertions(+), 49 deletions(-) create mode 100644 app/models/room_image.rb create mode 100644 app/uploaders/image_uploader.rb create mode 100644 app/views/manager/rooms/_form.html.slim create mode 100644 app/views/manager/rooms/_image.html.slim create mode 100644 app/views/manager/rooms/_room.html.slim create mode 100644 app/views/manager/rooms/edit.html.slim create mode 100644 app/views/manager/rooms/index.html.slim create mode 100644 db/migrate/20190823063416_create_room_images.rb rename db/migrate/{20190820001559_create_active_storage_tables.active_storage.rb => 20190828005029_create_active_storage_tables.active_storage.rb} (100%) diff --git a/Gemfile b/Gemfile index 5548d08..747325d 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,8 @@ gem "bootstrap4-kaminari-views" gem "config", "~> 2.0" gem "cocoon" gem "figaro" +gem "carrierwave", "~> 0.10.0" +gem "mini_magick", "~> 4.3" group :development, :test do gem "byebug", platforms: %i[mri mingw x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 5cd758a..f9c23ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -46,7 +46,7 @@ GEM io-like (~> 0.3.0) arel (9.0.0) ast (2.4.0) - autoprefixer-rails (9.6.1) + autoprefixer-rails (9.6.1.1) execjs bcrypt (3.1.13) bindex (0.8.1) @@ -61,6 +61,11 @@ GEM rails (>= 3.1) builder (3.2.3) byebug (11.0.1) + carrierwave (0.10.0) + activemodel (>= 3.2.0) + activesupport (>= 3.2.0) + json (>= 1.7) + mime-types (>= 1.16) childprocess (1.0.1) rake (< 13.0) chromedriver-helper (2.1.1) @@ -83,10 +88,10 @@ GEM crass (1.0.4) database_cleaner (1.7.0) deep_merge (1.2.1) - devise (4.6.2) + devise (4.7.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 4.1.0, < 6.0) + railties (>= 4.1.0) responders warden (~> 1.2.3) diff-lcs (1.3) @@ -141,6 +146,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) + json (2.2.0) kaminari (1.1.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.1.1) @@ -165,7 +171,11 @@ GEM marcel (0.3.3) mimemagic (~> 0.3.2) method_source (0.9.2) + mime-types (3.2.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2019.0331) mimemagic (0.3.3) + mini_magick (4.9.5) mini_mime (1.0.2) mini_portile2 (2.4.0) minitest (5.11.3) @@ -252,15 +262,14 @@ GEM sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (5.0.7) - railties (>= 4.0.0, < 6) + sass-rails (5.1.0) + railties (>= 5.2.0) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sassc (2.0.1) + sassc (2.1.0-x86_64-linux) ffi (~> 1.9) - rake sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -320,6 +329,7 @@ DEPENDENCIES bootstrap (~> 4.3.1) bootstrap4-kaminari-views byebug + carrierwave (~> 0.10.0) chromedriver-helper cocoon coffee-rails (~> 4.2) @@ -333,6 +343,7 @@ DEPENDENCIES jquery-rails kaminari (~> 1.1, >= 1.1.1) listen (>= 3.0.5, < 3.2) + mini_magick (~> 4.3) mysql2 (>= 0.4.4, < 0.6.0) pry-rails puma (~> 3.11) diff --git a/app/assets/javascripts/manager/custom.js b/app/assets/javascripts/manager/custom.js index ddf7354..80f5df8 100644 --- a/app/assets/javascripts/manager/custom.js +++ b/app/assets/javascripts/manager/custom.js @@ -9,6 +9,20 @@ function readURL(f, previewId) { } } +function previewImages() { + + var $preview = $('#preview').empty(); + if (this.files) $.each(this.files, readAndPreview); + + function readAndPreview(i, file) { + var reader = new FileReader(); + $(reader).on("load", function() { + $preview.append($("", {src:this.result, height:150, width:150})); + }); + reader.readAsDataURL(file); + } +} + $(document).ready(function(){ $('#admin_table').DataTable({ scrollY: 500, @@ -76,4 +90,7 @@ $(document).ready(function(){ }); $('[data-toggle="tooltip"]').tooltip(); + + $('.preview-image').on("change", previewImages); }); + diff --git a/app/assets/stylesheets/manager/custom.scss b/app/assets/stylesheets/manager/custom.scss index 22dacc6..3d7a26e 100644 --- a/app/assets/stylesheets/manager/custom.scss +++ b/app/assets/stylesheets/manager/custom.scss @@ -1,6 +1,7 @@ footer.sticky-footer { padding: 2rem 0; flex-shrink: 0; + float: left; .copyright { line-height: 1; font-size: 0.8rem; @@ -112,6 +113,7 @@ body.sidebar-toggled { .create-room{ margin: 30px 0; + width: 135px; } /* Style the sidenav links and the dropdown button */ @@ -344,3 +346,65 @@ a.account:hover { color: darkslategrey; text-decoration: none !important; } + +.image-detail{ + width: 400px; + border-radius: 4%; + height: 300px; + padding: 10px; +} + +td.action{ + padding: 0; +} + +.action{ + padding: 0 10px 0 10px; + margin: 0 10px 0 10px; +} + +.nested-image{ + float: left; + margin: 10px 0px; +} + +.nested-image:before { + content: 'x'; + color: #000000c4; + font-weight: 600; + font-family: Arial, sans-serif; + font-size: 28px; +} + +.nested-add-image{ + margin: 10px 0px; +} + +.show-image{ + width: 100%; + float: left; +} + +.thumb-image{ + float: left; + padding: 0 20px 25px 0; +} + +.links{ + width: 100%; + float: left; +} + +.submit{ + width: 100%; + float: left; +} + +.nested-image.btn.remove_fields.existing { + margin: -19px -50px 0; +} + +.preview-image{ + width: 200px; + float: left; +} diff --git a/app/controllers/manager/rooms_controller.rb b/app/controllers/manager/rooms_controller.rb index 623ee46..02799b8 100644 --- a/app/controllers/manager/rooms_controller.rb +++ b/app/controllers/manager/rooms_controller.rb @@ -2,8 +2,15 @@ module Manager class RoomsController < BaseController + before_action :load_room, only: %i[edit update] + + def index + @rooms = Room.sort_by_name + end + def new - @room = current_admin.rooms.build + @room = Room.new + @room.room_images.build end def edit; end @@ -11,9 +18,19 @@ def edit; end def create @room = current_admin.rooms.build room_params if @room.save - redirect_to manager_root_path, flash: { success: t(".create_room") } + upload_images + redirect_to manager_room_path(@room), success: t(".create_room") + else + render :new, danger: t(".can't_create") + end + end + + def update + if @room.update room_params + upload_images if params[:room_images] + redirect_to manager_room_path(@room), success: t(".update_success") else - render :new, flash: { danger: t(".can't_create") } + render :edit, danger: t(".update_fail") end end @@ -22,7 +39,18 @@ def create def room_params params.require(:room).permit :name, :address, :rate_point, :description, :guest, :type_room, :acreage, :bed_room, - :bath_room, :images, :location_id + :bath_room, :location_id, + room_images_attributes: %i[id room_id image _destroy] + end + + def load_room + @room = Room.find params[:id] + end + + def upload_images + params[:room_images]["image"].each do |a| + @room_images = @room.room_images.create!(image: a) + end end end end diff --git a/app/models/room.rb b/app/models/room.rb index 6fed287..6cf6b39 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true class Room < ApplicationRecord - has_many_attached :images belongs_to :location belongs_to :user + has_many :room_images validates :name, presence: true, length: { maximum: 50 } validates :address, presence: true @@ -13,4 +13,6 @@ class Room < ApplicationRecord validates :type_room, presence: true enum type_room: { private_room: 0, entire: 1 } + + accepts_nested_attributes_for :room_images, allow_destroy: true end diff --git a/app/models/room_image.rb b/app/models/room_image.rb new file mode 100644 index 0000000..5b94d99 --- /dev/null +++ b/app/models/room_image.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class RoomImage < ApplicationRecord + belongs_to :room + mount_uploader :image, ImageUploader + + validates :image, presence: true +end diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb new file mode 100644 index 0000000..fa5470b --- /dev/null +++ b/app/uploaders/image_uploader.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class ImageUploader < CarrierWave::Uploader::Base + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # # For Rails 3.1+ asset pipeline compatibility: + # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) + # + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :thumb do + process resize_to_fit: [150, 150] + 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/manager/rooms/_form.html.slim b/app/views/manager/rooms/_form.html.slim new file mode 100644 index 0000000..46c8539 --- /dev/null +++ b/app/views/manager/rooms/_form.html.slim @@ -0,0 +1,46 @@ += form_for [:manager, @room] do |f| + = render "shared/manager/error_messages", object: @room + + = f.label :name, class: "col-form-label" + = f.text_field :name, class: "form-control", required: true + + = f.label :locations, class: "col-form-label" + = f.select :location_id, options_for_select(build_location_for_rooms, + selected: f.object.location_id), {include_blank: t("please_choose_one")}, + {class: "form-control", required: true} + + = f.label :type_room, class: "col-form-label" + = f.select :type_room, options_for_select(select_of_types, + selected: f.object.type_room), {include_blank: t("please_choose_one")}, + {class: "form-control", required: true} + + = f.label :address, class: "col-form-label" + = f.text_field :address, class: "form-control", required: true + + = f.label :guest, class: "col-form-label" + = f.number_field :guest, class: "form-control", required: true + + = f.label :acreage, class: "col-form-label" + = f.text_field :acreage, class: "form-control", required: true + + = f.label :bed_room, class: "col-form-label" + = f.number_field :bed_room, class: "form-control", required: true + + = f.label :bath_room, class: "col-form-label" + = f.number_field :bath_room, class: "form-control", required: true + + = f.label :description, class: "col-form-label" + = f.text_area :description, class: "form-control", required: true + + = f.label :image, class: "col-form-label" + .show-image + = f.fields_for :room_images do |builder| + .nested-fields + - if builder.object.image? + = image_tag builder.object.image.thumb.url, class: "thumb-image" + = link_to_remove_association "", builder, class: "nested-image btn" + = f.file_field :image, multiple: true, name: "room_images[image][]", + class: "form-control preview-image", presence: true + #preview + .submit + = f.submit yield(:button_title), class: "create-room btn btn-outline-primary" diff --git a/app/views/manager/rooms/_image.html.slim b/app/views/manager/rooms/_image.html.slim new file mode 100644 index 0000000..de55f83 --- /dev/null +++ b/app/views/manager/rooms/_image.html.slim @@ -0,0 +1,4 @@ +.nested-fields + = f.file_field :image, multiple: true, name: "room_images[image][]", + class: "form-control preview-image", presence: true + = link_to_remove_association "remove", f, class: "btn btn-danger" diff --git a/app/views/manager/rooms/_room.html.slim b/app/views/manager/rooms/_room.html.slim new file mode 100644 index 0000000..a96c287 --- /dev/null +++ b/app/views/manager/rooms/_room.html.slim @@ -0,0 +1,10 @@ +tr + td + = room.name + td + = room.location.name + td + = room.type_room + td.action + = link_to t(".edit"), edit_manager_room_path(room), + class: "action btn btn-outline-info" diff --git a/app/views/manager/rooms/edit.html.slim b/app/views/manager/rooms/edit.html.slim new file mode 100644 index 0000000..9c4c96a --- /dev/null +++ b/app/views/manager/rooms/edit.html.slim @@ -0,0 +1,3 @@ +- provide(:button_title, t(".save")) +h1 = t(".edit_room") += render "form" diff --git a/app/views/manager/rooms/index.html.slim b/app/views/manager/rooms/index.html.slim new file mode 100644 index 0000000..21ca924 --- /dev/null +++ b/app/views/manager/rooms/index.html.slim @@ -0,0 +1,8 @@ +table#room_table.table.table-hover.table-striped + thead + th Name + th Location + th Type Room + th Action + tbody + = render @rooms diff --git a/app/views/manager/rooms/new.html.slim b/app/views/manager/rooms/new.html.slim index 96181b8..84be124 100644 --- a/app/views/manager/rooms/new.html.slim +++ b/app/views/manager/rooms/new.html.slim @@ -1,34 +1,3 @@ +- provide(:button_title,t(".create_room") ) h1 = t(".create_room") -= form_for [:manager, @room] do |f| - = render "shared/manager/error_messages", object: @room - - = f.label :name, class: "col-form-label" - = f.text_field :name, class: "form-control", required: true - - = f.label :locations, class: "col-form-label" - = f.select :location_id, options_for_select(build_location_for_rooms), {include_blank: t("please_choose_one")}, - {class: "form-control", required: true} - - = f.label :address, class: "col-form-label" - = f.text_field :address, class: "form-control", required: true - - = f.label :guest, class: "col-form-label" - = f.number_field :guest, class: "form-control", required: true - - = f.label :acreage, class: "col-form-label" - = f.text_field :acreage, class: "form-control", required: true - - = f.label :bed_room, class: "col-form-label" - = f.number_field :bed_room, class: "form-control", required: true - - = f.label :bath_room, class: "col-form-label" - = f.number_field :bath_room, class: "form-control", required: true - - = f.label :description, class: "col-form-label" - = f.text_area :description, class: "form-control", required: true - - = f.label :type_room, class: "col-form-label" - = f.select :type_room, options_for_select(select_of_types), - {include_blank: t("please_choose_one")}, {class: "form-control", required: true} - - = f.submit t(".create_room"), class: "create-room btn btn-outline-primary" += render "form" diff --git a/config/locales/en.yml b/config/locales/en.yml index adb806a..69b68ee 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,7 @@ en: please_choose_one: please choose one + sure: "Are you sure?" + layouts: manager: title: "Booking Homestays" @@ -12,11 +14,32 @@ en: create: "Create failed!" manager: rooms: - create_room: "Thanks you to create room" + create_room: "Thank you to create room" can't_create: "can not create room" don't_have_location: "Don't have location, Please Create Location" + update_success: Update Success! + update_fail: Update Failed + deleted_success: Deleted success new: create_room: Create Room + edit: + edit_room: Edit Rooms + save: Save + room: + edit: "Edit" + delete: "Delete" + show: + description: Description + room: Rooms + utility: Utilities + image: Images + guest: Guest + bed_room: Bed Rooms + bath_room: Bath Rooms + acreage: Acreage + address: Address + type_room: Type Rooms + shared: manager: left_menu: diff --git a/db/migrate/20190816042328_create_rooms.rb b/db/migrate/20190816042328_create_rooms.rb index b58c74b..b45f057 100644 --- a/db/migrate/20190816042328_create_rooms.rb +++ b/db/migrate/20190816042328_create_rooms.rb @@ -6,7 +6,7 @@ def change t.string :name t.string :address t.decimal :rate_point - t.string :description + t.text :description t.integer :guest t.integer :type_room, default: 0 t.decimal :acreage diff --git a/db/migrate/20190823063416_create_room_images.rb b/db/migrate/20190823063416_create_room_images.rb new file mode 100644 index 0000000..e0aea18 --- /dev/null +++ b/db/migrate/20190823063416_create_room_images.rb @@ -0,0 +1,10 @@ +class CreateRoomImages < ActiveRecord::Migration[5.2] + def change + create_table :room_images do |t| + t.references :room + t.string :image + + t.timestamps + end + end +end diff --git a/db/migrate/20190820001559_create_active_storage_tables.active_storage.rb b/db/migrate/20190828005029_create_active_storage_tables.active_storage.rb similarity index 100% rename from db/migrate/20190820001559_create_active_storage_tables.active_storage.rb rename to db/migrate/20190828005029_create_active_storage_tables.active_storage.rb diff --git a/db/schema.rb b/db/schema.rb index 48dd5d1..ad42e61 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_08_21_084727) do +ActiveRecord::Schema.define(version: 2019_08_28_005029) do create_table "active_storage_attachments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.string "name", null: false @@ -71,10 +71,29 @@ end create_table "prices", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + t.bigint "room_id" t.decimal "cost", precision: 8, scale: 2 t.decimal "cleaning_fee", precision: 8, scale: 2, default: "0.0" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["room_id"], name: "index_prices_on_room_id" + end + + create_table "room_images", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + t.bigint "room_id" + t.string "image" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["room_id"], name: "index_room_images_on_room_id" + end + + create_table "room_utilities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + t.bigint "room_id" + t.bigint "utility_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["room_id"], name: "index_room_utilities_on_room_id" + t.index ["utility_id"], name: "index_room_utilities_on_utility_id" end create_table "rooms", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| @@ -83,7 +102,7 @@ t.string "name" t.string "address" t.decimal "rate_point", precision: 10 - t.string "description" + t.text "description" t.integer "guest" t.integer "type_room", default: 0 t.decimal "acreage", precision: 10 @@ -111,6 +130,12 @@ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + create_table "utilities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "vouchers", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.string "code" t.decimal "sale", precision: 10 @@ -122,6 +147,9 @@ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "addresses", "areas" add_foreign_key "areas", "locations" + add_foreign_key "prices", "rooms" + add_foreign_key "room_utilities", "rooms" + add_foreign_key "room_utilities", "utilities" add_foreign_key "rooms", "locations" add_foreign_key "rooms", "users" end