こちらもなんとなくで意味を理解している、具体的な使い方のイメージができていない
の理由からしらべて記事を書くことにしました
##「hidden_field」とは
form_forやform_withの中で使用する
目に見えない値を送るイメージ
どうやら、「hidden_field_tag」ヘルパーもあるみたいだが
これらの違いはまた別の日に記事にする
##とりあえず、手を動かして使ってみる、準備編
ユーザーが投稿する画面を作って
投稿するまえに投稿の内容の確認画面を作成してみる
UserとPostのそれぞれのコントローラーとモデルを
作成してみる
~/environment/rails/sample_app
❯ rails g controller users
~/environment/rails/sample_app
❯ rails g model User
~/environment/rails/sample_app
❯ rails g controller posts index new create
~/environment/rails/sample_app
❯ rails g model Post
~/environment/rails/sample_app
❯ rails db:migrate
###アソシエーション
class User < ApplicationRecord
has_many :posts
end
class User < ApplicationRecord
has_many :user
end
###初期データを入れる
以前、自分が書いた記事をみつつ
UserとPostの初期データを入れる
以前書いた初期データを入れる記事
test_user = User.create!(
name: 'test',
email: 'test@mail.com',
password: 'password'
)
Post.create!(
title: 'test title',
contents: '投稿のテストです',
user_id: test_user.id
)
Post.create!(
title: 'test title2',
contents: '投稿のテスト、2回めです',
user_id: test_user.id
)
下記のコマンドで実行
rails db:seed
###一覧画面を作成
コントローラーの記載
何度もユーザーの取得を宣言するのは、面倒なので
privateメソッドで記述しておく
class PostsController < ApplicationController
before_action :set_user
def index
@posts = Post.where(user_id: @user.id)
end
private
def set_user
@user = User.find(1)
end
end
viewの作成
<h1>投稿一覧画面</h1>
<% @posts.each do |post| %>
<p><%= post.title %></p>
<p><%= post.contents %></p>
<% end %>
ルーティング定義
Rails.application.routes.draw do
get 'posts/index'
end
###投稿作成画面を作成
こちらもコントローラーの記載から
class PostsController < ApplicationController
before_action :set_user
def index
@posts = Post.where(user_id: @user.id)
end
def new
@posts = Post.new
end
def create
@posts = Post.create(
title: params[:post][:title],
contents: params[:post][:contents],
user_id: @user.id
)
if @posts.save
redirect_to posts_index_path
else
render :new
end
end
private
def set_user
@user = User.find(1)
end
end
「params[:title]
」として取得しようとしてつまずいた
パラメータの確認
**params[:モデル名][:渡したname属性]**で取得する
viewの作成
<h1>投稿新規作成画面</h1>
<%= form_with(model: @posts, url: posts_create_path, local: true) do |f| %>
<div id="container">
<%= f.text_field :title %>
<%= f.text_area :contents %>
<%= f.submit %>
</div>
<% end %>
ルーティング定義
Rails.application.routes.draw do
get 'posts/index'
# 追加
get 'posts/new'
post 'posts/create'
end
これでまずは普通のユーザーが投稿して
一覧画面までできた
##いよいよ確認画面を作成する
Postコントローラーに確認画面
用の「confirmアクション」を追加する
class PostsController < ApplicationController
before_action :set_user
# 追加
before_action :posts_params
def index
@posts = Post.where(user_id: @user.id)
end
def new
@posts = Post.new
end
# 確認画面用のアクション 追加
def confirm
@posts = Post.new(
title: params[:post][:title],
contents: params[:post][:contents]
)
# エラーが発生した場合true、エラーが無い場合falseを返す
if @posts.valid?
render :confirm
else
render :new
end
end
# 削除
def create
@posts = Post.create(
title: params[:post][:title],
contents: params[:post][:contents],
user_id: @user.id
)
if @posts.save
redirect_to posts_index_path
else
render :new
end
end
private
def set_user
@user = User.find(1)
end
# ストロングパラメーター追加
def posts_params
params.require(:post).permit(:title, :contents)
end
end
####「valid?」「invalid?」メソッド
こちらにも違いがあるみたい
「valid?」
バリデーションが実行された結果
エラーが無い場合trueを返し,エラーが発生した場合falseを返す
「invalid?」はその逆
ルーティングの定義から
Rails.application.routes.draw do
get 'posts/index'
get 'posts/new'
# 削除
post 'posts/create'
# 追加
post 'posts/confirm'
end
view作成
~/environment/rails/sample_app
❯ touch app/views/posts/confirm.html.erb
viewを修正していく
でも、まずは確認画面へ行くかテストしたいので
<h1>成功</h1>
だけ記入
フォームを送信した際に、URLが
localhost:3000/posts/confirm
になっていて
画面に「成功」の画面がでていればOK
###さらに細かく実装していく
アクションを追加する
class PostsController < ApplicationController
# ~割愛~
# 確認画面用のアクション
def confirm
@posts = Post.new(
title: params[:post][:title],
contents: params[:post][:contents]
)
# エラーが発生した場合true、エラーが無い場合falseを返す
# 後置ifで記述
render :confirm if @posts.valid?
end
# ~割愛~
end
viewを作成していく
<h1>確認画面</h1>
<%= form_with(model: @posts, url: posts_complete_path, local: true) do |f| %>
<div id="container">
# ここで登場、「hidden_field」
<%= f.hidden_field :title %>
<%= @posts.title%>
<%= f.hidden_field :contents %>
<%= @posts.contents%>
# パラメーターに対して名前をつけることができる、name属性
<%= f.submit '戻る', name: 'back' %>
<%= f.submit '送信する' %>
</div>
<% end %>
フォームの送信先に少し手こずる
・form_withは、デフォルトで「POST」で送信する
・コントローラーでcreateを使用してオブジェクトを作成するとnewとsaveを
行ってくれる
→そのため、フォームが「PATCH」で送信される
→「PATCH」はすでにオブジェクトがある場合に送信される
完了画面用のアクションを追加する
class PostsController < ApplicationController
# ~割愛~
# 確認画面用のアクション
def confirm
@posts = Post.new(
title: params[:post][:title],
contents: params[:post][:contents]
)
# エラーが発生した場合true、エラーが無い場合falseを返す
# 後置ifで記述
render :confirm if @posts.valid?
end
# 完了画面用のアクション
def complete
@posts = Post.new(
title: params[:post][:title],
contents: params[:post][:contents],
user_id: @user.id
)
# パラメーターに[:back]がついている(戻るボタン)をクリック
# もしくは、オブジェクトが保存されなかったら「new」の画面を戻す
render :new if params[:back] || !@posts.save
end
# ~割愛~
end
これで、投稿→確認→完了の画面遷移までができる
投稿の簡易アプリが完成
##戻るボタンを押した際に使用される「hidden_field」
作成したview
<h1>確認画面</h1>
<%= form_with(model: @posts, url: posts_complete_path, local: true) do |f| %>
<div id="container">
# ここで登場、「hidden_field」
<%= f.hidden_field :title %>
<%= @posts.title%>
作成されているHTML
<input type="text" name="post[title]" id="post_title">
内容を入力して、戻るボタンを押す
<input type="text" value="テスト タイトル" name="post[title]" id="post_title">
「value」の中に入力した値
がはいっている
ユーザが直接フォームから入力させないまま、値を受け渡したい時に使用する
##参考記事
https://railsguides.jp/action_view_overview.html
https://railsdoc.com/page/hidden_field
https://qiita.com/___xxx_/items/7c9b194230c7ce2b02ca
https://remonote.jp/rails-confirm-form
https://web-begginer-log.com/rails-confirm/