学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails

Ruby on Rails6.0 | 空き部屋を登録・予約・決済できるWebサイトを作成する 24 | 写真カルーセル表示

[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>
                                                    &nbsp;&nbsp;&nbsp;
                                                    <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>
                                                    &nbsp;&nbsp;&nbsp;
                                                    <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>
                                                    &nbsp;&nbsp;&nbsp;
                                                    <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>



[23]写真アップロード(dropzone)<< [ホームに戻る] >> [25]Googleマップ