0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

railsでコメントを自動保存してみた〜超ざっくり〜 改訂予定

Last updated at Posted at 2023-05-11

railsでQuiitaみたいな自動保存ってどうやってできるんだろうとふと思ったので、超ざっくり作成してみました。今後、より良くしていく予定ですが、現段階ではかなりざっくりです。

もし改善案とか教えてもらえると嬉しいです...

ビューの記述

show.html.haml
%form#comment
  %label{ for: 'comment_area' } コメント
  %textarea#comment_area{ name: 'interview_comment[comment]', value: (@comment if @comment)

= javascript_include_tag 'auto_save'

コントローラの記述

こちらはajaxでデータが送られてきます。
コメントがまだない場合は新しく作成し、ある場合はアップデートしています。

comments_controller.rb
class CommentsController < ApplicationController
  def new
    @comment = Comment.new
  end
   
  def show
    #差し当たりこの定義
    @comment = Comment.find(params[:id])
  end

  def create
    existing_comment = Comment.find_by(params[:id])
    
    if existing_comment
      existing_comment.update(comment: params[:comment])
    else
      new_comment = Comment.new(comment_params)
      new_comment.save
    end

    redirect_back(fallback_location: root_path)
  end

  private
  def comment_params
    params.require(:comment).permit(:comment)
  end
end

JSの記述

JSは長いこと触っていなかったので、出来上がってみると単純ですが、なかなか苦戦しました...
ajaxのurlの渡し方がわからず、様々に試しましたが、結局rails routesで出てくるurlでよかったです。

ajaxをJSでAJAXリクエストを直接記述することは可能みたいですが、CSRF保護、リモートフォーム処理などを手動で再実装する必要があるそうで、時間がかかりそうだったのでjQueryを使いました。

assets/javascripts/auto_save.js
// = require jquery2
const comment_area = document.getElementById('comment_area');

if (comment_area) {
  let timeoutId;

  const autosave = function() {
    const comment = comment_area.value; 
    const url = '/comments';

    $.ajax({
      url: url,
      type: 'POST',
      // dataはハッシュで指定
      data: { comment: comment },
      dataType: 'script'
    });
  };

  // フォームの変更を監視し、10秒ごとに自動保存を実行する
  comment_area.addEventListener('input', function() {
    clearTimeout(timeoutId); 
    timeoutId = setTimeout(autosave, 1000); 
  });
}

ただ、この自動保存だと問題を抱えています。以下は今後の課題です。

1、現状は1秒ごとに保存されるので、データベース負荷がかなり重そう。

これはどうやって解決できるのか...

すぐ思いつく方法では、以下の2つなんですが、どちらもなんかいけてない。
* セーブの間隔を長くする
* inputではなく、focusoutを使用する

2、今後保存するデータが増えたときに、それぞれに関数を適用していく必要がある。
例えば、「コメントした人の名前も保存したい」となった場合に、そちらのinputにも関数を適用させないといけない。また、最初を空欄にしておくとnilでデータが送られてしまうので、デフォルト値を設定しておけばいいのか?何がいいか分からない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?