1.実現したいこと
初学者です。Rails(5.2.3)にて、1日にメモを3つ書き残すような仕組みをアプリケーションで実現したいと考えております。「モデルを一括登録する手順」を参考に、3つのメモを一括登録することは出来ましたが、その日に登録済みであるメモを、一括編集することも可能にしたい(もしくは、実装の方法or方針自体に問題があればご指摘いただきたい)と考えております。
(目次)
1.実現したいこと
2.試したこと
3.コード
※ 環境… Rails5.2.3 / mySQL
※ ファイル構成…
「_form.html.haml」
→ 一括登録用フォーム。ここで一括編集も行いたい。createアクションは自動推測で呼べるが、updateアクションを呼び出せていない。
「memo_collection.rb」
→ 3つのメモを一括登録できるようにするために用意したmemo_collectionモデル。
「memos_controller.rb」
→ memoのコントローラ。updateアクションを呼び出すことが出来ていないので、ストロングパラメータ含め記述がまだ曖昧です。
※ Memoテーブル…
Column | Type | Options |
---|---|---|
user_id | integer | foreign_key: true, null:false |
memo | string | null:false |
Association -
- belongs_to :user
2.試したこと
「fields_forの上手な使い方」「form_withでnetsted_formを扱う方法」等も参考にさせて頂きましたが、一括編集の実現には至っておりません。
① 既に登録されているメモ「@todays_memos」のデータを使い、memo_collectionモデルを作成して、その際に各メモの主キーも読み込ませつつ、form_withに送り各メモidを判別させようとするも、エラー発生。方針はあっている気がするが実装方法が分からず挫折。
② form_withでの自動推測を諦め手動でパスできる方法を一次ソース等で調べたが、今回の場合でそれを実現する方法がわからない。
③ updateアクションへのパスは不可能と判断し、createメソッド内にて編集ロジックを組もうと思ったが、挫折。(そもそもナンセンスなやり方ですよね…)
④ 一括編集は不可能と判断し、「新規作成時に、その日登録済みのデータが存在した場合、先にそれらを全削除する」というロジックを組もうとしたが、これもナンセンスですね…
⑤ 一括編集は不可能と判断し、個別編集に切り替えたが、これではそもそものアプリケーションとしての要件を満たすことが出来ない。
参考にした記事
一括登録する方法はコチラを参考にしました → モデルを一括登録する手順
一括編集する方法はコチラを参考にしましたが、解決しませんでした → fields_forの上手な使い方 & form_withでnetsted_formを扱う方法
3.コード
※ 現時点では、編集画面で「保存する」を押すと、新たなレコードが3つ作成されてしまう…という状態です。
_form.html.haml(一括登録用フォーム。一括編集も出来ればここで行いたい…)
= form_with(model: memos, url: memos_path, local: true) do |form| - memos.collection.each do |memo| = fields_for 'memos[]', memo do |field| %br/ = field.text_field :memo %br/ = form.submit "保存する"
memo_collection.rb(3つのメモを一括で扱うためのモデル。)
class MemoCollection include ActiveModel::Conversion extend ActiveModel::Naming extend ActiveModel::Translation include ActiveModel::AttributeMethods include ActiveModel::Validations MEMO_NUM = 3 # 同時にユーザーを作成する数 attr_accessor :collection # 初期化メソッド def initialize(attributes = []) if attributes.present? self.collection = attributes.map do |value| Memo.new( memo: value['memo'], user_id: value['user_id'] ) end p self.collection else self.collection = MEMO_NUM.times.map{ Memo.new } end end # レコードが存在するか確認するメソッド def persisted? false end # コレクションをDBに保存するメソッド def save is_success = true ActiveRecord::Base.transaction do collection.each do |result| # バリデーションを全てかけたいからsave!ではなくsaveを使用 is_success = false unless result.save end # バリデーションエラーがあった時は例外を発生させてロールバックさせる raise ActiveRecord::RecordInvalid unless is_success end rescue p 'エラー' ensure return is_success end end
memos_controller.rb(memoコントローラ。updateアクションを呼び出すことが出来ていなく、中身記述もまだ曖昧。)
class MemosController < ApplicationController before_action :todays_memos, only: [:index, :update] def index @users = User.all @memos = MemoCollection.new end def create @memos = MemoCollection.new(memos_params) @memos.save redirect_to root_path end # 機能させることが出来ていないupdateアクション def update @todays_memos.update(update_memos_params) redirect_to root_path end private def memos_params params.require(:memos).map{|memo| memo.permit(:memo).merge(user_id: current_user.id)} end # 機能させることが出来ていないupdate用のストロングパラメータ def update_memos_params params.require(:memos).map{|memo| memo.permit(:id, :memo).merge(user_id: current_user.id)} end def todays_memos todays_memos = Memo.where(created_at: Time.current.all_day, user_id: current_user.id) if user_signed_in? @todays_memos = MemoCollection.new(todays_memos) if todays_memos.exists? end end
勉強不足で大変恐縮ですが、知恵をお貸しいただけば幸いです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/19 12:58