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

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

Rails6.1 | 民泊予約アプリ作成 | 23 | Application Helper

↓↓クリックして頂けると励みになります。


22 | Autocompleteとgeocoderの利用】 << 【ホーム】 >> 【24 | Google Maps


RailsのApplication Helper(アプリケーションヘルパー)は、Ruby on Railsフレームワークで使用される便益的なメソッドや関数を定義するためのユーティリティクラスです。
これらのヘルパーメソッドは、ビュー(View)やコントローラー(Controller)で共通のコードを抽象化し、再利用性を高めるために使用されます。
主にビューで使用され、ビューで表示のロジックやデータフォーマットを簡素化し、DRY(Don't Repeat Yourself)の原則に従います。

Application Helperは通常、app/helpers/application_helper.rbというファイルに定義されます。
このファイルに定義したヘルパーメソッドは、全てのビューで利用可能です。


カードで部屋の写真を表示させる際に使うヘルパーを作成します。
「app\assets\images」フォルダに「blank.jpg」ファイルを保存しておいてください。


「app\helpers\application_helper.rb」ファイルに以下の記述を追加します。

    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(11行目)

module ApplicationHelper

    def avatar_url(user)
        if user.avatar.attached?
            url_for(user.avatar)
        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



作成したヘルパーを使って、ビューを編集していきます。
まずは部屋コントローラーのshowメソッドに以下の記述を追加します。

@photos = @room.photos
@i = 0



記述追加 【app/controllers/rooms_controller.rb】28行目

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, :photo_upload, :delete_photo, :amenities, :location, :update]

  def index
     @rooms = Room.all
  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
    @i = 0
  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, :latitude, :longitude, :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」ファイルを編集します。


記述編集 「app/views/rooms/index.html.erb」

<div class="container mt-4">
    <div class="row">
        <% @rooms.each do |room| %>
            <% if room.active? %>
                <div class="col-md-3">
                    <div class="card">
                        <div class="card-body">
                            <%= link_to room_path(room), data: { turbolinks: false} do %>
                                <%= image_tag room_cover(room), style: "width: 100%;" %>
                                <h5 class="card-title mt-2">
                                    <span class="btn btn-light"><%= room.listing_name %></span>
                                </h5>
                            <% end %>
                            <div class="card-text" style="margin-left: 0.5rem;">
                                <p style="font-size: 0.8rem; margin-bottom: -0.3rem;">Address</p>
                                <p style="margin-bottom: 2rem;"><%= room.address %></p>

                                <%= link_to user_path(room.user), style: "text-decoration:none;" do %>
                                    <figure class="figure">
                                        <%= image_tag avatar_url(room.user), style: "width: 40px;", class: "figure-img img-fluid rounded-pill" %>
                                    </figure>
                                    <span class="badge bg-light text-dark" style="font-size: 0.9rem;"><%= room.user.full_name %></span>
                                <% end %>                    
                            </div>


                            <h5 class="badge rounded-pill bg-danger text-light" style="font-size: 1rem;">1泊<%= number_to_currency(room.price) %></h5>
                        </div>
                    </div>
                </div>
            <% end %>
        <% end %>
    </div>
</div>



ブラウザを確認します。
http://localhost:3000/rooms/

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



「app\views\rooms\show.html.erb」ファイルを編集します。


記述編集 【app\views\rooms\show.html.erb】

<div class="container mt-4">
    <div class="row">
        <!-- 右側 -->
        <div class="col-md-3">

            <!-- 予約フォーム -->

        </div>
        <!-- 左側 -->
        <div class="col-md-9 mb-4">

            <!-- カルーセル表示 -->
            <div class="card">
                <div class="card-body">

                    <div id="carouselExampleIndicators" class="carousel slide" data-bs-ride="carousel">
                        <div class="carousel-indicators">
                            <% @photos.each do |photo| %>
                                <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="<%= @i %>" class="<%= 'active' if photo.id == @photos[0].id %>" aria-current="true" aria-label="Slide <%= @i+1 %>"></button>
                                <% @i = @i +1 %>
                            <% end %>
                        </div>
                        <div class="carousel-inner">
                            <% @photos.each do |photo| %>
                                <div class="carousel-item <%= 'active' if photo.id == @photos[0].id %>">
                                    <%= image_tag url_for(photo), class: "d-block w-100", style: "border-radius: 10px;" %>
                                </div>
                            <% end %>
                        </div>
                        <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="prev">
                            <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                            <span class="visually-hidden">Previous</span>
                        </button>
                        <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide="next">
                            <span class="carousel-control-next-icon" aria-hidden="true"></span>
                            <span class="visually-hidden">Next</span>
                        </button>
                    </div>
                </div>
            </div>

            <div class="card mb-2 mt-2">
                <div class="card-body">
                    <h2 class="mb-4 mt-4"><%= @room.listing_name %></h2>

                    <div class="fs-5"><%= @room.address %></div>
                    <div class="mt-4">
                    <%= link_to user_path(@room.user), style: "text-decoration:none;" do %>
                        <%= image_tag avatar_url(@room.user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 40px; height: 30px;" %>
                        <span class="badge bg-light text-dark"><%= @room.user.full_name %></span>
                    <% end %>
                    </div>

                </div>
            </div>

            <!-- 部屋のインフォメーション -->
            <div class="card mb-2">
                <div class="card-body">    
                    <div class="row">
                        <div class="col-3">
                            <i class="fas fa-home fa-2x" style="color: cadetblue"></i><br/>
                            <%= @room.home_type %>
                        </div>
                        <div class="col-3">
                            <i class="fas fa-user fa-2x" style="color: cadetblue"></i><br/>
                            <%= pluralize(@room.accommodate, "人宿泊可能") %>
                        </div>
                        <div class="col-3">
                            <i class="fas fa-bed fa-2x" style="color: cadetblue"></i><br/>
                            <%= pluralize(@room.bed_room, "台") %>
                        </div>
                        <div class="col-3">
                            <i class="fas fa-door-closed fa-2x" style="color: cadetblue"></i><br/>
                            <%= pluralize(@room.bath_room, "部屋") %>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card">
                <div class="card-body">        
                    <div class="badge bg-secondary mb-4">部屋の詳細</div>
                    <p><%= @room.summary %></p>
                </div>
            </div>            

            <!-- アメニティ -->
            <div class="card mt-2">
                <div class="card-body">        
                    <div class="badge bg-secondary mb-4">アメニティ</div>

                    <div class="row">
                        <div class="col-6">
                            <ul style="list-style:none;">
                                <li class="<%= 'text-line-through' if !@room.is_tv %>"><span style="color: black;"><i class="fas fa-tv"></i>&nbsp;テレビ</span></li>
                                <li class="<%= 'text-line-through' if !@room.is_kitchen %>"><span style="color: black;"><i class="fas fa-blender"></i>&nbsp;キッチン</span></li>
                                <li class="<%= 'text-line-through' if !@room.is_internet %>"><span style="color: black;"><i class="fas fa-wifi"></i>&nbsp;Wi-Fi</span></li>
                            </ul>
                        </div>
                        <div class="col-6">
                            <ul style="list-style:none;">
                                <li class="<%= 'text-line-through' if !@room.is_heating %>"><span style="color: black;"><i class="fab fa-hotjar"></i>&nbsp;暖房</span></li>
                                <li class="<%= 'text-line-through' if !@room.is_air %>"><span style="color: black;"><i class="fas fa-temperature-low"></i>&nbsp;エアコン</span></li>
                            </ul>
                        </div>
                    </div>
                </div>           
            </div>
        </div>
    </div>
</div>



ブラウザを確認します。
写真はBootstrapのカルーセル表示を利用しています。
http://localhost:3000/rooms/1

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



ダッシュボードを更新します。
「app/views/users/dashboard.html.erb」ファイルを編集します。


記述編集 【app/views/users/dashboard.html.erb】

<div class="container mt-4 mb-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4">
            <div class="card mb-4">
                <div class="card-body">
                    <!-- アバター -->
                    <%= image_tag avatar_url(current_user), class: "img-fluid img-thumbnail rounded-pill" %>
                    <h4 style="margin-left: 5.5rem;"><%= current_user.full_name %></h4>
                    <!-- 画像アップロードボタン -->
                    <button class="btn btn-info text-light w-100" type="button" data-bs-toggle="collapse" data-bs-target="#collapse1" aria-expanded="false" aria-controls="collapse1">
                        <i class="fa-solid fa-cloud-arrow-up"></i>アバター画像アップロード
                    </button>
                    <div class="collapse" id="collapse1">
                    <div class="card card-body">
                        <%= form_for :user, url: users_edit_url(current_user), action: :update, method: :post do |f| %>
                            <%= f.file_field :avatar, class: "input-group-text", onchange: "this.form.submit();" %>
                        <% end %>   
                    </div>
                </div>
                <hr/>
                <div>
                    <%= link_to "部屋新規登録", new_room_path, class: "btn btn-danger" %>
                </div>
            
                <hr/>
                <!-- ステータス -->
                <div type="button" data-bs-toggle="collapse" data-bs-target="#collapse2" aria-expanded="false" aria-controls="collapse2">

                    <% if current_user.status %>
                        <span class="btn btn-success"><i class="toggle far fa-edit"></i>オンライン</span>
                    <% else %>
                        <span class="btn btn-secondary"><i class="toggle far fa-edit"></i>オフライン</span>
                    <% end %>                
                
                </div>
                <div class="collapse" id="collapse2">
                    <div class="card card-body">

                        <%= form_for :user, url: users_edit_url(current_user), action: :update, method: :post do |f| %>
                            <%= f.select(:status, options_for_select([["オンライン", true], ["オフライン", false]]), {}, {class: "custom-select"}) %>                        
                            <%= f.submit "保存", class: "btn btn-dark" %>
                        <% end %>

                    </div>
                </div>
                <hr/>
                <!-- 自己紹介 -->
                <div class="h5"><%= current_user.about %></div>
                <button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapse3" aria-expanded="false" aria-controls="collapse3">
                    自己紹介編集
                </button>

                <div class="collapse" id="collapse3">
                    <div class="card card-body">
                        <%= form_for :user, url: users_edit_url(current_user), action: :update, method: :post do |f| %>
                            <div><%= f.text_area :about, autofocus: true, autocomplete: 'form'%></div>
                            <%= f.submit "保存", class: "btn btn-dark" %>
                        <% end %>                        
                    </div>
                </div>
                <hr/>
                <!-- 電話番号 -->
                <div>
                    <% if !current_user.phone_number.blank? %>
                        <span class="pull-right icon-babu"><i class="far fa-check-circle" style="color:green;"></i></span>&nbsp;&nbsp;電話番号
                    <% else %>
                        <div class="text-danger">電話番号が登録されていません</div>
                        <%= link_to  "電話番号登録", edit_user_registration_path, class: "btn btn-danger" %>
                    <% end %>                    
                </div>
                <hr/>
                <!-- アカウント登録日 -->
                登録:<%= I18n.l(current_user.created_at, format: :full_date) %>                                
                
            </div>
        </div>


        </div>
        <!-- 右側 -->
        <div class="col-md-8">

            <!-- お知らせ -->
            <div class="card mb-2">
                <div class="card-body">
                    <h5 class="card-title">お知らせ</h5>
                    <h6 class="card-subtitle mb-2 text-body-secondary">
                    </h6>
                    <p class="card-text">
                    </p>    
                </div>
            </div>

            <!-- 登録している部屋 -->
            <div class="card">
                <div class="card-body">
                    <h5 class="card-title">登録している部屋</h5>
                    <h6 class="card-subtitle mb-2 text-body-secondary">
                    </h6>

                    <div class="row">
                        <% current_user.rooms.each do |room| %>
                            <% if room.active? %>
                                <div class="col-md-4">
                                    <div class="card mb-2">
                                        <div class="card-body">
                                            <%= link_to room_path(room), data: { turbolinks: false} do %>
                                                <%= image_tag room_cover(room), style: "width: 100%;" %>
                                                <h5 class="card-title">
                                                    <span class="btn btn-light"><%= room.listing_name %></span>
                                                </h5>
                                            <% end %>
                                            <div class="card-text" style="margin-left: 0.5rem;">
                                                <p style="font-size: 0.8rem; margin-bottom: -0.3rem;">Address</p>
                                                <p><%= room.address %></p>
                                                <h5 class="badge rounded-pill bg-danger text-light mb-4" style="font-size: 1rem;">1泊<%= number_to_currency(room.price) %></h5>               
                                                <%= link_to listing_room_path(room), class: "btn btn-outline-primary w-100 mb-4" do %>
                                                    登録内容編集
                                                <% end %>
                                              
                                            </div>
                             
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        <% end %>
                    </div>

                </div>
            </div>

        </div>
     
    </div>

</div>



ブラウザで確認します。
http://localhost:3000/dashboard

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



ユーザー情報紹介ページを更新します。
「app/views/users/show.html.erb」ファイルを編集します。


記述編集 【app/views/users/show.html.erb】

<div class="container mt-4 mb-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4 mb-4">
            <div class="card">
                <div class="card-body">

                    <!-- ステータス -->
                    <div>
                        <% if @user.status %>
                            <span class="badge bg-success"><i class="fa-regular fa-bell"></i>オンライン</span>
                        <% else %>
                            <span class="badge bg-secondary"><i class="fa-regular fa-bell-slash"></i>オフライン</span>
                        <% end %>                                   
                    </div>                
                    <!-- アバター -->
                    <%= image_tag avatar_url(@user), class: "img-fluid img-thumbnail rounded-pill" %>
                    <h4 class="text-center"><%= @user.full_name %></h4>   
                    
                    <!-- 自己紹介 -->
                    <div class="h5 text-center"><%= @user.about %></div>                           
                </div>
            </div>       

        </div>
        <!-- 右側 -->
        <div class="col-md-8">

            <!-- 登録している部屋 -->
            <div class="card mb-4">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんが登録している部屋</h5>

                    <div class="container mt-4">
                    <div class="row">
                        <% @user.rooms.each do |room| %>
                            <% if room.active? %>
                                <div class="col-md-4">
                                    <div class="card">
                                        <div class="card-body">
                                            <%= link_to room_path(room), data: { turbolinks: false} do %>
                                                <%= image_tag room_cover(room), style: "width: 100%;" %>
                                                <h5 class="card-title">
                                                    <span class="btn btn-light"><%= room.listing_name %></span>
                                                </h5>
                                            <% end %>
                                            <div class="card-text" style="margin-left: 0.5rem;">
                                                <p style="font-size: 0.8rem; margin-bottom: -0.3rem;">Address</p>
                                                <p style="margin-bottom: 2rem;"><%= room.address %></p>
                               
                                            </div>
                                
                                            <h5 class="badge rounded-pill bg-danger text-light" style="font-size: 1rem;">1泊<%= number_to_currency(room.price) %></h5>
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        <% end %>
                    </div>
                </div>

                </div>
            </div>

            <!-- レビュー -->
            <div class="card">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんへのレビュー</h5>
                    <h6 class="card-subtitle mb-2 text-body-secondary">
                    </h6>
                    <p class="card-text">
                    </p>    
                </div>
            </div>
        </div>     
    </div>
</div>



ブラウザを確認します。
ユーザ情報の詳細を他のユーザも確認できます。
http://localhost:3000/users/2

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



ナビゲーションバーに「部屋を登録する」リンクを追加します。


記述追加 【app/views/shared/_navbar.html.erb】36行目

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="/"><span class="font1">Vacation Rental</span></a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <!-- もしログインしていなかったら-->
        <% if (!user_signed_in?) %>
        <li class="nav-item" style="margin-bottom: 0.1rem;">
          <span style="margin-left: 1rem;">
          <%= link_to  "新規登録", new_user_registration_path, class: "btn btn-danger" %>
          </span>
        </li>
        <li class="nav-item">
          <span style="margin-left: 1rem;">
            <%= link_to  "ログイン", new_user_session_path, class: "btn btn-success text-light" %>
          </span>
        </li>
      </ul>
      <!-- ログインしていたら -->
      <% else %>
      <ul class="navbar-nav" style="margin-left: 2rem;">
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">

          <figure style="position:relative; top: 0.2rem;" class="avatar <%= current_user.status ? "online" : "offline" %>"></figure>  
          <%= image_tag avatar_url(current_user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 40px; height: 30px;" %>          
            <%= current_user.full_name %>
          </a>
          <ul class="dropdown-menu">
            <li><%= link_to  "ダッシュボード", dashboard_path, class: "dropdown-item btn btn-lightt" %></li>
            <li><%= link_to  "ユーザ登録情報編集", edit_user_registration_path, class: "dropdown-item btn btn-light" %></li>
            <li><hr class="dropdown-divider"></li>
            <li><%= link_to  "部屋を新規登録", new_room_path, class: "dropdown-item btn btn-light" %></li>
            <li><hr class="dropdown-divider"></li>
            <li><%= link_to  "ログアウト", destroy_user_session_path, method: :delete, class: "dropdown-item btn btn-light" %></li>
          </ul>
        </li>
      </ul>
      <% end %>

    </div>
  </div>
</nav>



ブラウザを確認します。

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



22 | Autocompleteとgeocoderの利用】 << 【ホーム】 >> 【24 | Google Maps


↓↓クリックして頂けると励みになります。