Rails6.0で作る交流会サイトの作成ログ(2)

▼免責事項
本記事により発生した如何なる損害についても当方は責任をおいません。

前回は、会員登録機能を作りました。

今回は、イベント機能投稿機能を作っていきたいと思います。

Rails6は、リッチテキストというブログ投稿みたいに編集できる機能が備わっています。

それを使って投稿機能を作っていきます。

$ rails action_text:install
$ rails db:migrate

さて、準備もできたら、早速作っていきましょう!今回、イベント情報で必要なのは次のデータです。

・イベント作成者
・タイトル
・イベントアイキャッチ画像
・カテゴリー
・参加定員
・開催場所
・会場名
・開催日
・開催時間
・イベント内容の詳細
・ステータス(下書き、公開中、終了)

今回はコマンドで打つのが面倒なので、マイグレーションファイルを作ってからカラムを登録します。

$ rails g scaffold Meeting
# db/migrate/作成したファイル.rb
class CreateMeetings < ActiveRecord::Migration[6.0]
 def change
   create_table :meetings do |t|
     t.references :user, foreign_key: true
     t.string :title
     t.text :body
     t.string :image
     t.string :category
     t.string :event_place
     t.string :event_address
     t.date :event_date
     t.time :open_time
     t.time :close_time
     t.integer :capacity
     t.integer :status

     t.timestamps
   end
   add_index :meetings, :title
   add_index :meetings, :category
   add_index :meetings, :event_address
   add_index :meetings, :event_date
   add_index :meetings, :open_time
   add_index :meetings, :body,length: 255 # 検索できる文字数が255文字と制限する。
   add_index :meetings, :status
 end
end
# app/models/meeting.rb

class Meeting < ApplicationRecord
 has_one_attached :image
 has_rich_text :body
 belongs_to :user
 validates :title, presence: true, length: { maximum: 200 }
 validates :body, presence: true
 validates :image, presence: true
 validates :category, presence: true
 validates :event_place, presence: true
 validates :event_address, presence: true
 validates :event_date, presence: true
 validates :open_time, presence: true
 validates :close_time, presence: true
 validates :capacity, presence: true
 validates :status, presence: true
end
# app/models/user.rb
class User < ApplicationRecord
 before_save { email.downcase! }
 validates :name, presence: true, length: { maximum: 50 }
 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
 validates :email, presence: true, length: { maximum: 255 },
                   format: { with: VALID_EMAIL_REGEX },uniqueness:  { case_sensitive: false }
 validates :password, presence: true, length: { minimum: 6 }, confirmation: true, unless: :uid?, on: :create
 validates :image, presence: true
 has_one_attached :image
 has_secure_password

 has_many :meetings, dependent: :destroy
end
# app/views/meetings/_form.html.erb
<%= form_with(model: meeting, local: true) do |form| %>
 <% if meeting.errors.any? %>
   <div id="error_explanation">
     <h2><%= pluralize(meeting.errors.count, "error") %> prohibited this meeting from being saved:</h2>

     <ul>
       <% meeting.errors.full_messages.each do |message| %>
         <li><%= message %></li>
       <% end %>
     </ul>
   </div>
 <% end %>

 <div class="field">
   <%= form.label "イベント画像" %>
   <%= form.file_field :image %>
   <% meeting.errors.full_messages_for(:image).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "タイトル" %>
   <%= form.text_field :title %>
   <% meeting.errors.full_messages_for(:title).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "カテゴリー" %>
   <%= form.select :category, [["勉強会", "勉強会"], ["セミナー", "セミナー"],  ["座談会", "座談会"], ["読書会", "読書会"],["相互コーチング", "相互コーチング"] ],  :prompt => "選択してください" %>
   <% meeting.errors.full_messages_for(:category).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "開催場所" %>
   <%= form.text_field :event_address %>
   <% meeting.errors.full_messages_for(:event_address).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "会場名" %>
   <%= form.text_field :event_place %>
   <% meeting.errors.full_messages_for(:event_place).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "開催日" %>
   <%= form.date_field :event_date,{} %>
   <% meeting.errors.full_messages_for(:event_date).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "開始時間" %>
   <%= form.time_field :open_time %>
   <% meeting.errors.full_messages_for(:open_time).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "終了時間" %>
   <%= form.time_field :close_time %>
   <% meeting.errors.full_messages_for(:close_time).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "定員人数" %>
   <%= form.number_field :capacity %>
   <% meeting.errors.full_messages_for(:capacity).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="field">
   <%= form.label "イベントの詳細" %>
   <%= form.rich_text_area :body %>
   <% meeting.errors.full_messages_for(:body).each do |message| %><p style="color:red"><i><%= message %></i></p><% end %>
 </div>

 <div class="actions">
   <%= form.submit "イベントを作成する" %>
   <small>※下書き状態になります。公開設定をしてください。</small>
 </div>
<% end %>
# app/controllers/meetings_controller.rb
class MeetingsController < ApplicationController
 before_action :set_meeting, only: [:show, :edit, :update, :destroy]

 # GET /meetings
 # GET /meetings.json
 def index
   @meetings = Meeting.all
 end

 # GET /meetings/1
 # GET /meetings/1.json
 def show
 end

 # GET /meetings/new
 def new
   @meeting = current_user.meetings.build
 end

 # GET /meetings/1/edit
 def edit
 end

 # POST /meetings
 # POST /meetings.json
 def create
   @meeting = current_user.meetings.build(meeting_params)
   @meeting.status = 1 # 0が公開状態、1が下書き状態

   respond_to do |format|
     if @meeting.save
       format.html { redirect_to @meeting, notice: 'Meeting was successfully created.' }
       format.json { render :show, status: :created, location: @meeting }
     else
       format.html { render :new }
       format.json { render json: @meeting.errors, status: :unprocessable_entity }
     end
   end
 end

 # PATCH/PUT /meetings/1
 # PATCH/PUT /meetings/1.json
 def update
   respond_to do |format|
     if @meeting.update(meeting_params)
       format.html { redirect_to @meeting, notice: 'Meeting was successfully updated.' }
       format.json { render :show, status: :ok, location: @meeting }
     else
       format.html { render :edit }
       format.json { render json: @meeting.errors, status: :unprocessable_entity }
     end
   end
 end

 # DELETE /meetings/1
 # DELETE /meetings/1.json
 def destroy
   @meeting.destroy
   respond_to do |format|
     format.html { redirect_to meetings_url, notice: 'Meeting was successfully destroyed.' }
     format.json { head :no_content }
   end
 end

 private
   # Use callbacks to share common setup or constraints between actions.
   def set_meeting
     @meeting = Meeting.find(params[:id])
   end

   # Never trust parameters from the scary internet, only allow the white list through.
   def meeting_params
     params.require(:meeting).permit(:title,:body,:image,:category,:event_place,:event_address,:event_date,:open_time,:close_time,:capacity,:status)
   end
end
# app/views/meetings/show.html.erb

<p id="notice"><%= notice %></p>

<p>
 <strong>イベント作成者:</strong>
 <%= @meeting.user.name %>
</p>

<p>
 <strong>タイトル:</strong>
 <%= @meeting.title %>
</p>

<p>
 <strong>Image:</strong>
 <%= image_tag @meeting.image,style: "width:300px;" %>
</p>

<p>
 <strong>category:</strong>
 <%= @meeting.category %>
</p>

<p>
 <strong>event_place:</strong>
 <%= @meeting.event_place %>
</p>

<p>
 <strong>event_address:</strong>
 <%= @meeting.event_address %>
</p>

<p>
 <strong>event_date:</strong>
 <%= @meeting.event_date %>
</p>


<p>
 <strong>open_time~close_time:</strong>
 <%= @meeting.open_time %> ~ <%= @meeting.close_time %>
</p>

<p>
 <strong>status:1が下書き状態、0が公開中</strong>
 <%= @meeting.status %>
</p>
<p>
 <strong>イベント詳細:</strong>
 <%= @meeting.body %>
</p>


<%= link_to 'Edit', edit_meeting_path(@meeting) %> |
<%= link_to 'Back', meetings_path %>

いやー、諸々長い編集でしたね。

では、諸々確認していきましょう!まずは、イベント投稿ページ

イベント詳細のところに、文章を編集できるボタンが色々並んでいますよね。

これが、rails6.0から追加された新機能です!すごいですね。

では、実際に投稿してみましょう!

イベントの詳細のところは、装飾機能が動作するか埋め込み画像が表示されるかも確認してください。

あれ・・・。画像が表示されてない。

ちょっと、色々調べて原因はよくわからんけど、blobの取り扱い方が間違っているらしい。

自動で作られている、_blob.html.erbを修正します。

# app/views/active_storage/blobs/_blob.html.erb

<figure class="attachment attachment--preview attachment--<%= blob.filename.extension %>">
 <%= image_tag blob %>

 <figcaption class="attachment__caption">
   <% if caption = blob.try(:caption) %>
     <%= caption %>
   <% else %>
     <span class="attachment__name"><%= blob.filename %></span>
     <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
   <% end %>
 </figcaption>
</figure>

これで、もう一度見てみましょう!

今度は完璧です!!!

いやー、なかなか長かったですねw

私はここまで4時間ほどかかりました(笑)

さてさて、次はここまで作ったアプリをherokuにデプロイして行きますー。




サポートしていただけると、泣いて喜びます! 嬉しくて仕事をめちゃめちゃ頑張れます。