戻る

Rails6.0


民泊サイトの構築 Rails6.0

  (0)
3,000円

タスク4-7   レビュー

このタスクについて


タスクの内容を一部抜粋します。
プロジェクトを購入していただくとこのタスクの内容の全てを読みやすい表示で見ることができます。
プログラムコードが色分けされて見やすくなります。
プログラムコードに行番号が付きます。
本文が色分けされて見やすくなります。
そしてこのアプリケーションのフルコードをダウンロードすることが可能になります。




「raty-js」をインストールします。



コマンド
yarn add raty-js


「app\assets\stylesheets\application.scss」ファイルに以下の記述を追加します。


記述追加 app\assets\stylesheets\application.scss(27行目)
@import 'raty-js/lib/jquery.raty';



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';

 @import 'raty-js/lib/jquery.raty';



「app\javascript\packs\application.js」ファイルに以下の記述を追加します。


記述追加 app\javascript\packs\application.js(14行目)
require("raty-js")



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")
require('jquery');
require("jquery-ui/ui/widgets/datepicker");
require("raty-js")

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")


レビューモデルを作成します。



コマンド
一文です。
rails g model Review review:text stars:bigint room:references reservation:references guest:references host:references type


コマンド
rails g model GuestReview --parent=Review --migration=false


コマンド
rails g model HostReview --parent=Review --migration=false


記述更新 db\migrate\20200727021130_create_reviews.rb
「,default: 1」の記述追加(5行目)と「, foreign_key: { to_table: :users }」の記述追加(8,9行目)をしています。
class CreateReviews < ActiveRecord::Migration[6.0]

  def change
    create_table :reviews do |t|
      t.text :review
      t.bigint :stars, default: 1
      t.references :room, null: false, foreign_key: true
      t.references :reservation, null: false, foreign_key: true
      t.references :guest, foreign_key: { to_table: :users }
      t.references :host, foreign_key: { to_table: :users }
      t.string :type
      t.timestamps
    end
  end
end



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


記述追加 app\models\guest_review.rb
「belongs_to :guest, class_name: "User"」の追加(2行目)
class GuestReview < Review
    belongs_to :guest, class_name: "User"
end



記述追加 app\models\host_review.rb
「belongs_to :host, class_name: "User"」の追加(2行目)
class HostReview < Review
    belongs_to :host, class_name: "User"
end



「app\models\review.rb」ファイルを以下のように編集します。


記述追加 app\models\review.rb
4行目と5行目に「, class_name: "User"」の記述を追加しています。
class Review < ApplicationRecord

  belongs_to :room
  belongs_to :reservation
  belongs_to :guest, class_name: "User"
  belongs_to :host, class_name: "User"
end


「app\models\room.rb」ファイルを編集していきます。


1.6行目に「has_many :guest_reviews」の記述追加


2.7行目に「has_many :reviews」の記述追加


3.21行目に「average_rating()」メソッドの追加
def average_rating
    guest_reviews.count == 0 ? 0 : guest_reviews.average(:stars).round(2).to_i
  end  



記述追加 app\models\room.rb

class Room < ApplicationRecord

  belongs_to :user

  has_many :reservations
  has_many :guest_reviews
  has_many :reviews

  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

  def average_rating
    guest_reviews.count == 0 ? 0 : guest_reviews.average(:stars).round(2).to_i
  end  
end



「app\models\reservation.rb」ファイルを編集します。


記述追加 app\models\reservation.rb
5行目に「has_many :reviews」の記述追加
class Reservation < ApplicationRecord

  belongs_to :user
  belongs_to :room

  has_many :reviews
end



「app\models\user.rb」ファイルを編集していきます。


5, 6行目に以下の記述を追加します。
has_many :guest_reviews, class_name: "GuestReview", foreign_key: "guest_id"
has_many :host_reviews, class_name: "HostReview", foreign_key: "host_id"



記述追加 app\models\user.rb
class User < ApplicationRecord

  has_many :rooms
  has_many :reservations
  has_many :guest_reviews, class_name: "GuestReview", foreign_key: "guest_id"
  has_many :host_reviews, class_name: "HostReview", foreign_key: "host_id"

  has_one_attached :avatar
  
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable

  validates :full_name, presence: true, length: {maximum: 50}
end


レビューコントローラを作成します。



「app\controllers」フォルダに「host_reviews_controller.rb」ファイルを新規作成してください。


app\controllers\host_reviews_controller.rb(新規作成したファイル)
class HostReviewsController < ApplicationController

    def create
        
      # ステップ 1: 予約が存在するかどうかを確認します(room_id、guest_id、host_id)  
      # ステップ 2: 現在のホストがこの予約のゲストをすでにレビューしているかどうかを確認します。
  
      @reservation = Reservation.where(
                      id: host_review_params[:reservation_id],
                      room_id: host_review_params[:room_id],
                      user_id: host_review_params[:guest_id]
                     ).first
  
      if !@reservation.nil?
  
        @has_reviewed = HostReview.where(
                          reservation_id: @reservation.id,
                          guest_id: host_review_params[:guest_id]
                        ).first
  
        if @has_reviewed.nil?
            # レビューを許可
            @host_review = current_user.host_reviews.create(host_review_params)
            flash[:success] = "レビューを作成しました。"
        else
            # レビュー済み
            flash[:success] = "この予約はレビュー済みです。"
        end
      else
        flash[:alert] = "予約がありません。"
      end
  
      redirect_back(fallback_location: request.referer)
    end
  
    def destroy
      @host_review = Review.find(params[:id])
      @host_review.destroy
  
      redirect_back(fallback_location: request.referer, notice: "削除しました。")
    end
  
    private
      def host_review_params
        params.require(:host_review).permit(:review, :stars, :room_id, :reservation_id, :guest_id)
      end
  end



「app\controllers」フォルダに「guest_reviews_controller.rb」ファイルを新規作成して下さい。


app\controllers\guest_reviews_controller.rb(新規作成したファイル)
class GuestReviewsController < ApplicationController

    def create
      # ステップ 1: 予約が存在するかどうかを確認します(room_id、host_id、host_id)
      # ステップ 2: 現在のホストがこの予約のゲストをすでにレビューしているかどうかを確認します。
  
      @reservation = Reservation.where(
                      id: guest_review_params[:reservation_id],
                      room_id: guest_review_params[:room_id]
                     ).first
  
      if !@reservation.nil? && @reservation.room.user.id == guest_review_params[:host_id].to_i
  
        @has_reviewed = GuestReview.where(
                          reservation_id: @reservation.id,
                          host_id: guest_review_params[:host_id]
                        ).first
  
        if @has_reviewed.nil?
            # レビューを許可
            @guest_review = current_user.guest_reviews.create(guest_review_params)
            flash[:success] = "レビューを作成しました。"
        else
            # レビュー済み
            flash[:success] = "この予約はレビュー済みです。"
        end
      else
        flash[:alert] = "予約がありません。"
      end
  
      redirect_back(fallback_location: request.referer)
    end
  
    def destroy
      @guest_review = Review.find(params[:id])
      @guest_review.destroy
  
      redirect_back(fallback_location: request.referer, notice: "削除しました。")
    end
  
    private
      def guest_review_params
        params.require(:guest_review).permit(:review, :stars, :room_id, :reservation_id, :host_id)
      end
  end



記述追加 app\controllers\rooms_controller.rb
「show()」メソッドに「@guest_reviews = @room.guest_reviews」の記述を追加してます。(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, :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
    @guest_reviews = @room.guest_reviews
  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

  # 予約 開始日のAJAX
  def preload
    today = Date.today
    reservations = @room.reservations.where("start_date >= ? OR end_date >= ?", today, today)
    render json: reservations
  end

  # 予約 終了日のAJAX
  def preview
    start_date = Date.parse(params[:start_date])
    end_date = Date.parse(params[:end_date])
    output = {
      conflict: is_conflict(start_date, end_date, @room)
    }
    render json: output
  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

    # 予約 プライベートメソッド
    def is_conflict(start_date, end_date, room)
      check = room.reservations.where("? < start_date AND end_date < ?", start_date, end_date)
      check.size > 0? true : false
    end
  end



「app\controllers\users_controller.rb」ファイルを編集します。


11行目に以下の記述を追加します。
# ユーザーがホストの場合、ホストに対するすべてのゲストレビューを表示
@guest_reviews = Review.where(type: "GuestReview", host_id: @user.id)
# ユーザーがゲストの場合、ユーザに対するすべてのホストレビューを表示
@host_reviews = Review.where(type: "HostReview", guest_id: @user.id)



app\controllers\users_controller.rb
class UsersController < ApplicationController

  before_action :authenticate_user!

  def dashboard
  end

  def show
    @user = User.find(params[:id])
    @rooms = @user.rooms
    # ユーザーがホストの場合、ホストに対するすべてのゲストレビューを表示
    @guest_reviews = Review.where(type: "GuestReview", host_id: @user.id)
    # ユーザーがゲストの場合、ユーザに対するすべてのホストレビューを表示
    @host_reviews = Review.where(type: "HostReview", guest_id: @user.id)
  end

  def update
    @user = current_user
    if @user.update_attributes(current_user_params)
      flash[:notice] = "保存しました"
    else
      flash[:alert] = "更新できません"
    end
    redirect_to dashboard_path
  end

  private
  def current_user_params
    params.require(:user).permit(:about, :status, :avatar)
  end
end


ルートを設定します。

35, 36行目に以下の記述を追加します。
  resources :guest_reviews, only: [:create, :destroy]
  resources :host_reviews, only: [:create, :destroy]



記述追加 config\routes.rb
Rails.application.routes.draw do

  # ルートを app\views\pages\home.html.erb に設定
  root 'pages#home'

  devise_for :users, 
              path: '', 
              path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'},
              controllers: {registrations: 'registrations'}

  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show', as: 'user'
  get '/your_trips' => 'reservations#your_trips'
  get '/your_reservations' => 'reservations#your_reservations'
  
  post '/users/edit', to: 'users#update'

  resources :rooms, except: [:edit] do
    member do
      get 'listing'
      get 'pricing'
      get 'description'
      get 'photo_upload'
      get 'amenities'
      get 'location'
      get 'preload'
      get 'preview'
      delete :delete_photo
      post :upload_photo
    end
    resources :reservations, only: [:create]
  end

  resources :guest_reviews, only: [:create, :destroy]
  resources :host_reviews, only: [:create, :destroy]

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end


レビュービューを作成します。



「app\views」フォルダに「reviews」フォルダを新規作成します。
作成した「reviews」フォルダに「_guest_form.html.erb」ファイルを新規作成してください。



app\views\reviews\_guest_form.html.erb(新規作成したファイル)
<a class="button is-small is-outlined is-danger toggle-modal" aria-control="<%= reservation.id %>">レビュー</a>
<div class="modal" id="<%= reservation.id %>">
    <div class="modal-background"></div>
    <div class="modal-content">
        <div class="box">
            <%= form_for GuestReview.new do |f| %>
                <%= f.hidden_field :reservation_id, value: reservation.id %>
                <div class="field">
                    <div id="star_<%= reservation.id %>"></div>
                </div>
                <div class="field">
                    <%= f.text_area :review, class: "textarea" %>
                </div>
                <%= f.hidden_field :room_id, value: reservation.room.id %>
                <%= f.hidden_field :reservation_id, value: reservation.id %>
                <%= f.hidden_field :host_id, value: reservation.room.user.id %>
                <a class="toggle-modal button is-light" aria-control="<%= reservation.id %>">キャンセル</a>
                <%= f.submit "レビューする", class: "button is-danger" %>
            <% end %>
        </div>
    </div>
</div>
<script>
    $('.toggle-modal').on('click', (e) => {
        e.stopPropagation();
        e.preventDefault();
        var reservation_id = e.target.getAttribute('aria-control');
        $('#star_' + reservation_id).raty({
            path: '/assets/raty-js/lib/images',
            scoreName: 'guest_review[stars]',
            score: 1
        });
        $('#star_' + reservation_id).raty('reload');
        $('#' + reservation_id).toggleClass('is-active');
    });
</script>




この続きはプロジェクトを購入していただくことで見ることができます。
プロジェクトを購入していただくとこのタスクの内容の全てを読みやすい表示で見ることができます。
プログラムコードが色分けされて見やすくなります。
プログラムコードに行番号が付きます。
本文が色分けされて見やすくなります。
そしてプロジェクトを購入するとこのアプリケーションのフルコードをダウンロードすることができます。

まだレビューはありません。

民泊サイトの構築 Rails6.0

3,000円

Rails6.0で民泊サイトを構築します。
ホストは部屋を登録し、ゲストは宿泊予約できます。
ゲストはクレジットカードで支払いをし、ホストには料金の80%が自動で口座に振り込まれます。
Googleマップによる表示、AJAX検索、日付カレンダーによる予約ができます。
リアルタイムメッセージにより連絡がとれます。
予約確認メールの送信も可能。
写真のアップロード機能、アマゾンS3の利用方法も解説。
レビュー機能の実装方法解説。
フルカレンダー による予約管理。
HEROKUへのデプロイ方法を解説。
フルコードのダウンロード可能。

タスク数: 128