前提
Ruby 2.7.2
Rails 6.0.3.4
gem 'bootstrap_form'を利用
状況をシンプルにするためにscafforldでpost title:string
のみ作った状況です。
実際にやりたいのはpostではありませんが、同意であり、わかりやすいのでpostとして進めています。
使っていないcreateやdestroyは消してあります。
実現したいこと
- indexにて、postsの個別の編集ができる
- indexから編集した時、遷移先はindex
- 失敗時、バリデーションエラーがviewに反映される
- 遷移後のURLはindex
- editにて個別編集もできる
- @posts = Post.allの量は多くないものとする(100以下)
上記の条件をクリアした実装はできたが、良い実装なのか不安です。
実装方法
例: indexからpost(id:1)のupdateが失敗した時
flash[:error]
にpost.errors
の値を渡すredirect_to posts_path
でindexにリダイレクトする- indexの
@posts
からposts(id:1)
を探す @posts(id:1)
にerrorsを追加(flash[:error]
からエラー内容を取得する)@posts(id:1).errors
に値が入っているため、view上にエラーが反映する
疑問
1.画面の遷移先をrefererで確認して条件分岐しているが、もっと良いやり方がないか?
ruby
1referer_uri = URI.parse(request.referer) 2if referer_uri.path == posts_path 3 ... 4end
2.redirect_to
でindexにリダイレクトし、バリデーションエラー内容をflash[:error]
で渡しているが、よい方法がないか?
render :index
だと、URLがposts/1
になる。
その状態でリロードするとeditに遷移してしまうので、URLはposts
にしたい。
ruby
1def index 2 @posts = Post.all 3 @posts.each { |post| post.if_eq_add_errors_to_self(flash[:error]['post']) } if flash[:error]&.key?('post') 4end 5 6def update 7 @post = Post.find(params[:id]) 8 if @post.update(post_params) 9 redirect_to posts_path, notice: 'Post was successfully updated.' 10 else 11 redirect_to posts_path, flash: { error: @post.flash_error_hash } 12 end 13end
該当のソースコード
posts_controller.rb
ruby
1class PostsController < ApplicationController 2 def index 3 @posts = Post.all 4 @posts.each { |post| post.if_eq_add_errors_to_self(flash[:error]['post']) } if flash[:error]&.key?('post') 5 end 6 7 def edit 8 @post = Post.find(params[:id]) 9 end 10 11 def update 12 @post = Post.find(params[:id]) 13 referer_uri = URI.parse(request.referer) 14 15 if @post.update(post_params) 16 if referer_uri.path == posts_path 17 redirect_to posts_path, notice: 'Post was successfully updated.' 18 else 19 redirect_to @post, notice: 'Post was successfully updated.' 20 end 21 elsif referer_uri.path == posts_path 22 redirect_to posts_path, flash: { error: @post.flash_error_hash } 23 else 24 render :edit 25 end 26 end 27 28 private 29 30 def post_params 31 params.require(:post).permit(:title) 32 end 33end 34
post.rb
ruby
1class Post < ApplicationRecord 2 validates :title, presence: true 3 4 def if_eq_add_errors_to_self(flash_error_post) 5 return unless id == flash_error_post['id'] 6 7 flash_error_post['details'].each do |col_key, details| 8 details.each { |detail| errors.add(col_key, detail['error'].to_sym) } 9 end 10 end 11 12 def flash_error_hash 13 { post: { id: id, details: errors.details } } 14 end 15end
index.html.erb
erb
1<%= render partial: 'form', collection: @posts, as: 'post' %>
edit.html.erb
erb
1<%= render 'form', post: @post %>
_form.html.erb
erb
1<%= bootstrap_form_with(model: post, local: true, inline_errors: false) do |f| %> 2 <%= f.text_field :title %> 3 <%= f.errors_on :title %> 4 <%= f.submit '更新する' %> 5<% end %> 6
実際の画面イメージ
回答1件
あなたの回答
tips
プレビュー