大学生が集まるプログラミングコミュニティ
GeekSalon(https://bit.ly/2M64LXd) 名古屋メンタ-の吉田です。
・セレクトボックスでカラムに入れるものを選択したい!
・投稿先をindexだけじゃなく、複数のページにも出来るようにしたい!
とういう人のための記事です。また
・投稿ボタンを押した後、セレクトした先にすぐ飛びたい!
というわがままな要望も[応用]として解決法を載せています。
是非参考にして下さい
##まずはセレクトボックスをつけてみよう
form_with, form_for でこんな感じのセレクトボックスをつけてみましょう
こちらの記事を参考につけてみて下さい(丸投げ)
https://qiita.com/kawakami_shotaro/items/11a677bf34136cb7686d
##ゴール:複数のページに投稿出来るようにする
今回はユーザーが「和食・洋食・中華」の3つのジャンルから投稿先を選択するという機能を実装してみます。
##用意するもの
- tweetsテーブルのgenreカラム(命名は自由です)
- viewページ(今回はpage1,page2,page3を用意)
まずはこの2つを用意しましょう
コマンドプロンプトを開きtweetsテーブルにgenreカラムを追加していきましょう。自分のプロダクトの階層にcdして
rails g migration AddGenreToTweets genre:integer
rails db:migrate
カラムを追加=>データベースに変更を加える=>migrateでしたね。カラムの用意はこれで完了です(保存形式がintegerの理由は後ほど)
viewページはVScodeで3つパパッと作ってしまいましょう。名前はpage1,page2,page3と適当につけておきます(忘れた人は教材で確認!)
##本題:投稿先をindexだけじゃなく、複数のページにも出来るようにする
では実装するためのコードを書いていきましょう。投稿ページのプルダウンのコードはこんな感じです
<%= stylesheet_link_tag 'new', :media => "all" %>
<div class="post-container">
<p class="title">投稿フォーム</p>
<%= form_for(@tweet, :url => { controller:'tweets', action:'create'})do |f| %>
<%= f.label :投稿内容 %>
<br>
<%= f.text_field :body,size: 140%>
-----ここから変更-----
<%= f.select :genre, [["和食", 1], ["洋食", 2], ["中華", 3]], include_blank: "選択して下さい" %>
-----ここまで------
<div class="field">
<%= f.label :画像選択 %>
<%= f.file_field :image %>
</div>
<br>
<%= f.submit "送信" %>
<br>
<% end %>
</div>
表示は和食ですが、実際カラムに入ってるのは1という風にしています(なので保存形式をintegerにしました)
次はコントローラーを変更しましょう
*省略*
def page1
@washokus = Tweet.where(genre: 1)
end
def page2
@yoshokus = Tweet.where(genre: 2)
end
def page3
@chukas = Tweet.where(genre: 3)
end
*省略*
private
def tweet_params
params.require(:tweet).permit(:body,:image,:genre)
end
順に見ていきましょう
def page1
@washokus = Tweet.where(genre: 1)
end
これは「genreカラムに1が入っているものだけを@washokusに代入」しています
この@washokusをpage1のviewで使うことで和食の投稿のみ表示されるように出来ます
private
def tweet_params
params.require(:tweet).permit(:body,:image,:genre)
end
genreカラムに入れたものを運べるよう、ストロングパラメーターにgenreを追加しましょう。これ結構忘れがちです
続いてルーティングを設定しましょう
get 'tweets/page1' => 'tweets#page1'
get 'tweets/page2' => 'tweets#page2'
get 'tweets/page3' => 'tweets#page3'
余談ですが、ルーティングを書く際はidを扱うコードより上にこれらのコードを書くようにしましょう
(例:get 'tweets/:id' => 'tweets#show', as: 'tweet'
)
これはidにurlが入ってエラーになるのを防ぐためです
最後にviewページを作ってあげましょう
<%= stylesheet_link_tag 'index', :media => "all" %>
<h1>和食</h1>
<div class="tweets-container">
<% @washokus.each do |t| %>
<div class="tweet">
<%= link_to t.user.name, user_path(t.user.id) %>
(♡<%= t.liked_users.count %>)
<% if t.image.present? %>
<%= image_tag t.image_url, :size => "500x300" %>
<% end %>
<div class="main-box">
<div class="left-container"><%= t.body %></div>
<div class=right-container>
<%= link_to "詳細", tweet_path(t.id) %>
<% if current_user.id == t.user.id %>
<%= link_to "編集", edit_tweet_path(t.id) %>
<%= link_to "削除", tweet_path(t.id), method: :delete %>
<% end %>
</div>
</div>
<p class="time"><%= t.created_at %></p>
</div>
<% end %>
</div>
<%= stylesheet_link_tag 'index', :media => "all" %>
<h1>洋食</h1>
<div class="tweets-container">
<% @yoshokus.each do |t| %>
<div class="tweet">
<%= link_to t.user.name, user_path(t.user.id) %>
(♡<%= t.liked_users.count %>)
<% if t.image.present? %>
<%= image_tag t.image_url, :size => "500x300" %>
<% end %>
<div class="main-box">
<div class="left-container"><%= t.body %></div>
<div class=right-container>
<%= link_to "詳細", tweet_path(t.id) %>
<% if current_user.id == t.user.id %>
<%= link_to "編集", edit_tweet_path(t.id) %>
<%= link_to "削除", tweet_path(t.id), method: :delete %>
<% end %>
</div>
</div>
<p class="time"><%= t.created_at %></p>
</div>
<% end %>
</div>
<%= stylesheet_link_tag 'index', :media => "all" %>
<h1>中華</h1>
<div class="tweets-container">
<% @chukas.each do |t| %>
<div class="tweet">
<%= link_to t.user.name, user_path(t.user.id) %>
(♡<%= t.liked_users.count %>)
<% if t.image.present? %>
<%= image_tag t.image_url, :size => "500x300" %>
<% end %>
<div class="main-box">
<div class="left-container"><%= t.body %></div>
<div class=right-container>
<%= link_to "詳細", tweet_path(t.id) %>
<% if current_user.id == t.user.id %>
<%= link_to "編集", edit_tweet_path(t.id) %>
<%= link_to "削除", tweet_path(t.id), method: :delete %>
<% end %>
</div>
</div>
<p class="time"><%= t.created_at %></p>
</div>
<% end %>
</div>
あとはこれらのページに飛べるよう、適当にリンクをindexに貼っておきましょう
<%= link_to '和食', :controller => "tweets", :action => "page1" %>
<%= link_to '洋食', :controller => "tweets", :action => "page2" %>
<%= link_to '中華', :controller => "tweets", :action => "page3" %>
これで完成です!お疲れ様でした!
##[応用]投稿ボタンを押した後、セレクト先にすぐ飛ぶ機能
今のtweetsコントローラーはcreateアクションで
if @tweet.save
redirect_to :action => "index"
となっているので、投稿後はindexに飛ぶようになっています。これを変更します
def create
@tweet = Tweet.new(tweet_params)
@tweet.user_id = current_user.id
if @tweet.save and @tweet.genre == 1
redirect_to :action => "page1"
elsif @tweet.save and @tweet.genre == 2
redirect_to :action => "page2"
elsif @tweet.save and @tweet.genre == 3
redirect_to :action => "page3"
else
redirect_to :action => "index"
end
end
A and Bは「AかつB」という条件を指します。つまりこの場合「"@tweetが保存される"かつ"genreカラムが1と合致する"」という条件を満たした場合、page1アクションが実行され、その結果page1にそのまま飛ぶようになっています。
セレクトボックスで何も選択しなかったり、保存に失敗した場合はindexに飛ぶようになってますね。