[23]写真アップロード(dropzone)<< [ホームに戻る] >> [25]Googleマップ
写真をカルーセル表示できるようにします。
「yarn」コマンドで「bulma-extensions」をインストールします。
コマンド
yarn add bulma-extensions
「app\javascript\packs\application.js」ファイルを以下のように書き換えます。
1.記述追加 app\javascript\packs\application.js(13行目)
window.BulmaCarousel = require("bulma-extensions/bulma-carousel/dist/js/bulma-carousel")
2.書き換え app\javascript\packs\application.js(15行目)
$(document).on('turbolinks:load', () => {
app\javascript\packs\application.js
// This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. require("@rails/ujs").start() require("turbolinks").start() require("@rails/activestorage").start() require("channels") window.Noty = require("noty") window.Dropzone = require("dropzone") window.BulmaCarousel = require("bulma-extensions/bulma-carousel/dist/js/bulma-carousel") $(document).on('turbolinks:load', () => { $('.toggle').on('click', (e) => { e.stopPropagation(); e.preventDefault(); $('#' + e.target.getAttribute('aria-controls')).toggleClass('is-hidden'); }) }) // Uncomment to copy all static images under ../images to the output folder and reference // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) // or the `imagePath` JavaScript helper below. // // const images = require.context('../images', true) // const imagePath = (name) => images(name, true) require("trix") require("@rails/actiontext")
「app\assets\stylesheets\application.scss」ファイルに以下の記述を追加します。
記述追加 app\assets\stylesheets\application.scss(19行目)
@import 'bulma-extensions/bulma-carousel/dist/css/bulma-carousel.min';
app\assets\stylesheets\application.scss
/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * *= require_tree . *= require_self */ @import 'bulma'; @import 'bulma-extensions'; @import 'bulma-extensions/bulma-carousel/dist/css/bulma-carousel.min'; @import 'noty/lib/noty'; @import 'noty/lib/themes/sunset'; @import 'dropzone/dist/basic.css'; @import 'dropzone/dist/dropzone.css';
「app\assets\images」フォルダに「blank.jpg」ファイルを保存しておいてください。
記述追加 app\helpers\application_helper.rb(13行目)
def room_cover(room) if room.photos.attached? url_for(room.photos[0]) else ActionController::Base.helpers.asset_path('blank.jpg') end end
app\helpers\application_helper.rb
module ApplicationHelper def avatar_url(user) if user.avatar.attached? url_for(user.avatar) elsif user.image? user.image else ActionController::Base.helpers.asset_path('icon_default_avatar.jpg') end end def room_cover(room) if room.photos.attached? url_for(room.photos[0]) else ActionController::Base.helpers.asset_path('blank.jpg') end end end
記述追加 app\controllers\rooms_controller.rb(26行目)
def show @photos = @room.photos end
app\controllers\rooms_controller.rb
class RoomsController < ApplicationController protect_from_forgery except: [:upload_photo] before_action :set_room, except: [:index, :new, :create] before_action :authenticate_user!, except: [:show] before_action :is_authorised, only: [:listing, :pricing, :description, :photo_upload, :amenities, :location, :update] def index @rooms = current_user.rooms end def new @room = current_user.rooms.build end def create @room = current_user.rooms.build(room_params) if @room.save redirect_to listing_room_path(@room), notice: "保存しました。" else flash[:alert] = "問題が発生しました。" render :new end end def show @photos = @room.photos end def listing end def pricing end def description end def photo_upload end def amenities end def location end def update new_params = room_params new_params = room_params.merge(active: true) if is_ready_room if @room.update(new_params) flash[:notice] = "保存しました。" else flash[:alert] = "問題が発生しました。" end redirect_back(fallback_location: request.referer) end def upload_photo @room.photos.attach(params[:file]) render json: { success: true } end def delete_photo @image = ActiveStorage::Attachment.find(params[:photo_id]) @image.purge redirect_to photo_upload_room_path(@room) end private def set_room @room = Room.find(params[:id]) end def room_params params.require(:room).permit(:home_type, :room_type, :accommodate, :bed_room, :bath_room, :listing_name, :summary, :address, :is_tv, :is_kitchen, :is_air, :is_heating, :is_internet, :price, :active, :description) end def is_authorised redirect_to root_path, alert: "権限がありません。" unless current_user.id == @room.user_id end def is_ready_room !@room.active && !@room.price.blank? && !@room.listing_name.blank? && !@room.photos.blank? && !@room.address.blank? end end
app\views\rooms\index.html.erb
<section class="section"> <div class="container"> <div class="columns"> <!-- 左側 --> <div class="column is-one-third"> <div class="columns is-multiline"> <!-- 上部 --> <div class="column is-full"> <div class="card"> <!--アバター --> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-256x256"> <%= image_tag avatar_url(current_user), class: "is-rounded" %> </figure> </div> <div class="card-content"> <!-- アカウント --> <article class="media"> <div class="media-content">アカウント登録日</div> <div class="media-right"> <strong><%= I18n.l(current_user.created_at, format: :full_date) %></strong> </div> </article> <hr class="h-10"> <!-- ステータス --> <article> <div class="media"> <div class="media-right"> <% if current_user.status %> <strong style="color: green">オンライン</strong> <% else %> <strong style="color: red">オフライン</strong> <% end %> </div> </div> </article> <hr class="h-10"> <br/> <!-- 自己紹介 --> <article> <div class="media"> <div class="media-content"> <p> <strong>自己紹介</strong> <br/> <br/> <%= current_user.about %> </p> </div> </article> </div> </div> </div> </div> </div> <!-- 右側 --> <div class="column"> <div class="columns is-multiline"> <!-- お部屋を登録する --> <div class="column is-one-third has-text-centered"> <%= link_to new_room_path do %> <div class="card"> <div class="card-image card-content is-horizontal-center is-flex "> <figure class="image is-256x256 "> <%= image_tag 'icon_add.png' %> </figure> </div> <div class="card-content"> <strong>お部屋を新規登録する</strong> </div> </div> <% end %> </div> <!-- 登録したお部屋 --> <% current_user.rooms.each do |room| %> <% if room.active? %> <div class="column is-one-third"> <div class="card"> <div class="card-image"> <%= link_to listing_room_path(room) do %> <figure class="image is-4by3"> <%= image_tag room_cover(room) %> </figure> <% end %> </div> <br/> <div class="card-content p-t-5 p-b-5"> <p class="subtitle is-6 m-b-5"><%= link_to room.listing_name, room_path(room), data: { turbolinks: false} %></p> <p class="subtitle is-6 m-b-5"><%= room.address %></p> <!--レビュー --> </div> <footer class="card-footer"> <a class="has-text-danger is-block card-footer-item has-text-right"> <span class="small-title">1泊の宿泊価格</span> <strong><%= number_to_currency(room.price) %></strong> </a> </footer> </div> </div> <% end %> <% end %> </div> </div> </div> </div> </section>
app\views\rooms\show.html.erb
<section class="section"> <div class="container"> <div class="columns"> <!-- 写真 --> <div class="card"> <div class="card-content"> <div class="content"> <%= image_tag room_cover(@room) %> </div> </div> </div> <br/> </div> </div> </section> <section class="section"> <div class="container"> <div class="columns"> <!-- 左側 --> <div class="column is-two-thirds"> <div class="columns is-multiline"> <div class="column"> <div class="card"> <div class="card-content"> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> <!-- お部屋の名前 --> <div class="row"> <div class="col-md-8"> <h1><%= @room.listing_name %></h1> <h2><%= @room.address %></h2> </div> </div> </div> </div> </article> </div> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> <span class="title is-5"><%= @room.user.full_name %></span> <figure class="image is-96x96"> <%= image_tag avatar_url(@room.user), class: "is-rounded" %> </figure> </div> </div> </article> </div> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> <!-- 部屋のインフォメーション --> <div style="white-space: nowrap"> <span class="col-md-3"> <i class="fas fa-home fa-3x" style="color: #1dbf73"></i> <span class="col-md-3"><%= @room.home_type %></span> </span> <span class="col-md-3"> <i class="fas fa-user fa-3x" style="color: #1dbf73"></i> <span class="col-md-3"><%= pluralize(@room.accommodate, "人") %></span> </span> <span class="col-md-3"> <i class="fas fa-bed fa-3x" style="color: #1dbf73"></i> <span class="col-md-3"><%= pluralize(@room.bed_room, "台") %></span> </span> <span class="col-md-3"> <i class="fas fa-bath fa-3x" style="color: #1dbf73"></i> <span class="col-md-3"><%= pluralize(@room.bath_room, "部屋") %></span> </span> </div> </div> </div> </article> </div> <!-- お部屋の詳細 --> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> <h3>お部屋の詳細</h3> <p><%= @room.description %></p> </div> </div> </article> </div> <!-- アメニティー --> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> <div class="row"> <div class="col-md-3"> <h4>アメニティ</h4> </div> <div class="col-md-9"> <div class="row"> <div class="col-md-6"> <ul class="amenities"> <li class="<%= 'text-line-through' if !@room.is_tv %>">テレビ</li> <li class="<%= 'text-line-through' if !@room.is_kitchen %>">キッチン</li> <li class="<%= 'text-line-through' if !@room.is_internet %>">インターネット</li> </ul> </div> <div class="col-md-6"> <ul class="amenities"> <li class="<%= 'text-line-through' if !@room.is_heating %>">暖房</li> <li class="<%= 'text-line-through' if !@room.is_air %>">エアコン</li> </ul> </div> </div> </div> </div> </div> </div> </article> </div> </div> </div> </div> <!-- カルーセル表示 --> <div class="column is-full"> <div class="card"> <div class="card-content"> <div class="hero-carousel" id="carousel-photo"> <% @room.photos.each do |photo| %> <div class="carousel-item has-background image is-16by9"> <%= image_tag url_for(photo), class: "is-background", width: "100%" %> </div> <% end %> </div> </div> </div> </div> <div class="column"> <div class="card"> <div class="card-content"> <!-- googleマップ --> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> </div> </div> </article> </div> <!-- 近くのお部屋 --> <div class="box"> <article class="media"> <div class="media-content"> <div class="content"> </div> </div> </article> </div> </div> </div> </div> </div> </div> <!-- 右側 --> <div class="column"> <div class="columns is-multiline"> <!-- 予約 --> <div class="column is-full"> <div class="card"> <div class="card-content"> <div class="media"> </div> </div> </div> </div> </div> </div> </div> </div> </section> <script> BulmaCarousel.attach('#carousel-photo', { slidesToScroll: 1, slidesToShow: 1 }); $(document).ready(function() { $('#tabs li').on('click', function() { var type = $(this).data('tab'); $('#tabs li').removeClass('is-active'); $(this).addClass('is-active'); $('.tab-content').hide(); $('#tab-' + type).show(); }) }) </script>
ブラウザ確認
表示されるか確認して下さい。
http://localhost:3000/rooms
http://localhost:3000/rooms/1
ナビゲーションバーにリンクを追加します。
記述追加 app\views\shared\_navbar.html.erb(62,63行目)
<%= link_to "お部屋を新規登録", new_room_path, class: "navbar-item" %> <%= link_to "登録したお部屋一覧", rooms_path, class: "navbar-item" %>
app\views\shared\_navbar.html.erb
<nav class="navbar is-light" role="navigation" aria-label="main navigation"> <div class="navbar-brand"> <a class="navbar-item" href="/"> <h1>テストサイトMinpaku6</h1> </a> <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> </div> <div id="navbarBasicExample" class="navbar-menu"> <div class="navbar-start"> <div class="navbar-item"> </div> </div> <div class="navbar-end"> <a class="navbar-item"></a> <a class="navbar-item"></a> <!-- もしログインしていなかったら--> <% if (!user_signed_in?) %> <div class="navbar-item"> <div class="buttons"> <%= link_to "新規ユーザ登録", new_user_registration_path, class: "button is-white" %> <%= link_to "ログイン", new_user_session_path, class: "button is-white" %> </div> </div> <!-- ログインしていたら --> <% else %> <div class="navbar-item has-dropdown is-hoverable" style="margin-right: 100px;"> <a class="navbar-item"> <figure class="image is-48x48 m-r-5"> <div style="margin-top: 0.6rem;"> <%= image_tag avatar_url(current_user), class: "is-rounded" %> </div> </figure> <%= current_user.full_name %> </a> <div class="navbar-dropdown"> <%= link_to "ユーザ登録情報編集", edit_user_registration_path, class: "navbar-item" %> <a href="" class="navbar-item"></a> <hr class="navbar-divider"> <%= link_to "ログアウト", destroy_user_session_path, method: :delete, class: "navbar-item" %> </div> </div> <% end %> </div> </div> </nav> <% if (user_signed_in?) %> <nav class="navbar has-shadow" style="z-index: 3;"> <div class="container"> <div class="navbar"> <%= link_to 'ダッシュボード', dashboard_path, class: "navbar-item" %> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link">ホスト</a> <div class="navbar-dropdown"> <%= link_to "お部屋を新規登録", new_room_path, class: "navbar-item" %> <%= link_to "登録したお部屋一覧", rooms_path, class: "navbar-item" %> </div> </div> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link">ゲスト</a> <div class="navbar-dropdown"> <a class="navbar-item"></a> <a class="navbar-item"></a> </div> </div> </div> </div> </nav> <% end %> <script> $(document).ready(function() { // navbar burgerアイコンでクリックイベントを確認する $(".navbar-burger").click(function() { // 「navbar-burger」と「navbar-menu」の両方で「is-active」クラスを切り替える $(".navbar-burger").toggleClass("is-active"); $(".navbar-menu").toggleClass("is-active"); }); }); </script>
↓↓クリックして頂けると励みになります。