railsでQuiitaみたいな自動保存ってどうやってできるんだろうとふと思ったので、超ざっくり作成してみました。今後、より良くしていく予定ですが、現段階ではかなりざっくりです。
もし改善案とか教えてもらえると嬉しいです...
ビューの記述
%form#comment
%label{ for: 'comment_area' } コメント
%textarea#comment_area{ name: 'interview_comment[comment]', value: (@comment if @comment)
= javascript_include_tag 'auto_save'
コントローラの記述
こちらはajaxでデータが送られてきます。
コメントがまだない場合は新しく作成し、ある場合はアップデートしています。
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を使いました。
// = 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でデータが送られてしまうので、デフォルト値を設定しておけばいいのか?何がいいか分からない。