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

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

Ruby on Rails6.0 | 空き部屋を登録・予約・決済できるWebサイトを作成する 77 | Bootstrap | Googleマップ

「25 | Googleマップ」をBootstrapに書き換えます。
設定部分は省略します。


Google Cloud PlatformにGoogleアカウントでログインしてAPIキーを取得してください。
手順は以下の通りにお願いします。
mrradiology.hatenablog.jp


記述追加 GemFile(73行目)

#googleマップ
gem 'geocoder', '~> 1.4'



GemFile

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.6'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# Use Puma as the app server
gem 'puma', '~> 4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

# Bulma
gem 'bulma-rails', '~> 0.7.4'
gem 'bulma-extensions-rails', '~> 1.0.30'

# デバイス
gem 'devise'

# 日本語化
gem 'rails-i18n'

# アマゾンS3
gem "aws-sdk"

# アクションテキスト画像表示
gem "mini_magick"
gem 'image_processing', '~> 1.2'

#googleマップ
gem 'geocoder', '~> 1.4'



コマンド
bundle


コマンド
rails g migration AddFieldsToRoom latitude:float longitude:float


コマンド マイグレーション
rails db:migrate


記述追加 app\models\room.rb(8行目)

  geocoded_by :address
  after_validation :geocode, if: :address_changed?



app\models\room.rb

class Room < ApplicationRecord

  belongs_to :user

  has_many_attached :photos
  has_rich_text :description

  geocoded_by :address
  after_validation :geocode, if: :address_changed?

  validates :home_type, presence: true
  validates :room_type, presence: true
  validates :accommodate, presence: true
  validates :bed_room, presence: true
  validates :bath_room, presence: true

end



GoogleマップAPIの埋め込み
取得したキーを「key=」から「&callback」の間に埋め込んで下さい。

<script async defer src="https://maps.googleapis.com/maps/api/js?key=ここにご自分のAPIキーを埋め込みます&callback=initMap" type="text/javascript"></script>



このscriptタグをサイトに埋め込みます。


app\views\rooms\show.html.erb

<!-- 写真 -->
<div class="row" style="margin-left: 10px; margin-right: 10px;">
    <div class="col-md-11">
        <div class="card">
            <div class="card-body">
                <%= image_tag room_cover(@room), width: "100%" %>
            </div>
        </div>
    </div>
</div>
<br/>

<div class="row" style="margin-left: 10px; margin-right: 10px;">
    <!-- 左パネル -->
    <div class="col-md-8">
        <!-- お部屋の名前 -->
        <div class="row">
            <div class="col-md-11">
                <div class="card">
                    <div class="card-body">
                        <h2><%= @room.listing_name %></h2>
                        <%= @room.address %>

                        <div class="text-right">
                            <%= image_tag avatar_url(@room.user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 40px; height: 30px;" %>
                            <%= @room.user.full_name %>
                        </div>

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

        </div>
        <br/>
        <!-- 部屋のインフォメーション -->
        <div class="row text-babu">
            <div class="col-md-11">
                <div class="card">
                    <div class="card-body">    

                        <div class="row text-center row-space-1">
                            <div class="col-md-3">
                                <i class="fas fa-home fa-3x" style="color: #1dbf73"></i><br/>
                                <%= @room.home_type %>
                            </div>
                            <div class="col-md-3">
                                <i class="fas fa-user fa-3x" style="color: #1dbf73"></i><br/>
                                <%= pluralize(@room.accommodate, "人宿泊可能") %>
                            </div>
                            <div class="col-md-3">
                                <i class="fas fa-bed fa-3x" style="color: #1dbf73"></i><br/>
                                <%= pluralize(@room.bed_room, "台") %>
                            </div>
                            <div class="col-md-3">
                                <i class="fas fa-door-closed fa-3x" style="color: #1dbf73"></i><br/>
                                <%= pluralize(@room.bath_room, "部屋") %>
                            </div>
                        </div>

                    </div>

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

        <br/>
        <!-- 詳細 -->
        <div class="row">
            <div class="col-md-11">
                <div class="card">
                    <div class="card-body">        
                        <h3>お部屋の詳細</h3>
                        <p><%= @room.description %></p>

                    </div>
                </div>
            </div>
        </div>
        <br/>
        <!-- アメニティ -->
        <div class="row">
        
            <div class="col-md-3" style="margin-left: 20px;">
                <h4>アメニティ</h4>
            </div>
            <div class="col-md-8">
                <div class="row">
                    <div class="col-md-5">
                        <ul class="amenities">
                            <li class="<%= 'text-line-through' if !@room.is_tv %>"><i class="fas fa-tv"></i>&nbsp;テレビ</li>
                            <li class="<%= 'text-line-through' if !@room.is_kitchen %>"><i class="fas fa-blender"></i>&nbsp;キッチン</li>
                            <li class="<%= 'text-line-through' if !@room.is_internet %>"><i class="fas fa-wifi"></i>&nbsp;インターネット</li>
                        </ul>
                    </div>
                    <div class="col-md-5">
                        <ul class="amenities">
                            <li class="<%= 'text-line-through' if !@room.is_heating %>"><i class="fab fa-hotjar"></i>&nbsp;暖房</li>
                            <li class="<%= 'text-line-through' if !@room.is_air %>"><i class="fas fa-temperature-low"></i>&nbsp;エアコン</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>            
        <br/>
        <!-- レビュー -->

        <br/>

        <!-- カルーセル表示 -->
        <div class="row">
            <div class="col-md-11">
                <div id="carouselExampleControls" class="carousel slide" data-ride="carousel">

                <% if @photos.length > 0 %>    

                    <ol class="carousel-indicators">
                        <% @photos.each do |photo| %>
                            <li data-target="#carouselExampleIndicators" data-slide-to="<%= photo.id %>" class="<%= 'active' if photo.id == @photos[0].id %>"></li>

                        <% end %>
                    </ol>

                    <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: "bd-placeholder-img bd-placeholder-img-lg d-block w-100", width: "100%" %>
                            </div>
                        <% end %>


                        <a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
                        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                        <span class="sr-only">Previous</span>
                        </a>
                        <a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
                        <span class="carousel-control-next-icon" aria-hidden="true"></span>
                        <span class="sr-only">Next</span>
                        </a>

                <% end %>
                    </div>
            </div>
        </div>

        <hr/>

        <!-- googleマップ -->
        <div class="col-md-11" style="margin-top: 30px;">

            <div id="map" style="width: 100%; height: 600px"></div>
            <script src="https://maps.googleapis.com/maps/api/js"></script>
            <script>
                function initialize() {
                    var location = {lat: <%= @room.latitude %>, lng: <%= @room.longitude %>};
                    var map = new google.maps.Map(document.getElementById('map'), {
                    center: location,
                    zoom: 14
                    });
                    var marker = new google.maps.Marker({
                    position: location,
                    map: map
                    });
                    var infoWindow = new google.maps.InfoWindow({
                    content: '<div id="content"><%= image_tag room_cover(@room), style: "width: 300px;", :alt => '' %></div>'
                    });
                    infoWindow.open(map, marker);
                }
                google.maps.event.addDomListener(window, 'load', initialize);
            </script>
            <script async defer src="https://maps.googleapis.com/maps/api/js?key=ここにご自分のAPIキーを入れてください&callback=initMap" type="text/javascript"></script>

        </div>

        <!-- 近くのお部屋を検索 -->
        <h4 style="margin-top: 30px; margin-left: 30px; margin-right: 30px;">
            近くのお部屋
        </h4>  
        <div class="row" style="margin-left: 30px; margin-right: 30px;">

            <% for room in @room.nearbys(10) %>
                <div class="col-6 col-md-3">
                    <%= image_tag room_cover(room), style: "width: 100%; height: 180;" %>
                    <h5 class="card-title"><%= link_to room.listing_name, room, data: { turbolinks: false} %></h5>
                    <footer>(距離:<%= room.distance.round(2) %> Km)</footer>
                </div>

            <% end %>

        </div>

    </div>

</div>

<!-- 右パネル -->
<div class="col-md-4">
    <!-- 予約フォーム -->
    
</div>



「config\initializers」フォルダに「geocoder.rb」ファイルを新規作成します。


config\initializers\geocoder.rb(新規作成したファイル)

Geocoder.configure(
  units: :km
)



ブラウザ確認
お部屋を登録するときに住所を入力すると自動で位置情報が保存されます。(Geocordingの機能)
ただし、日本の住所に対する変換が貧弱なので「北海道札幌市中央区」くらいまでしか認識してくれません。

http://localhost:3000/rooms/1/location


住所を入力して位置情報が更新されるか確かめてみます。

住所更新
住所更新


位置情報更新
位置情報更新



部屋を2つ以上登録して公開します。
http://localhost:3000/rooms/new


お部屋のページを確認します。
http://localhost:3000/rooms/1

マップ表示の確認
マップ表示の確認