9
8

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 5 years have passed since last update.

Rails / Ajaxを使って画面遷移しない一時保存機能をつける

Posted at

ブログを更新しました。元の記事はコチラ


先日つけてみたソーシャルボタンですが、やっぱ数字が出るってモチベーションになっていいね。意外とPocketも多いんだなぁ。
今回もまたRails。投稿サイトとかでよくある、一時保存機能をやってみた。文章書いていると、何かの拍子で「あ!」てなることが多いから、あるとユーザーに優しい。

###フォーム


<div class="blog-form">
	<%= form_for(@post) do |f| %>

		<%= f.text_field :tilte %>
		<%= f.text_area :body %>
		<!-- for temporal saving -->
		<div class="create-temp"></div>
		<%= f.submit "送信する" %>
		
	<% end %>
</div>

フォームは例えばこんな感じ。
一時保存するかどうかのフラグと、行われた後のメッセージ表示用に class="create-temp" がついた div を置いている。
  
###コントローラー


	def create
		@post = current_user.posts.build(strong_params)
		if @post.save
			redirect_to @post
		else
			render 'new'
		end
	end

	def create_temp
		@post = current_user.posts.build(strong_params)
		@post.published = false
		@post.save
	end

createアクションの他に、一時保存用に、create_tempというのを作った。current_userとかstrong_paramsとかは、人によっていろいろでしょうが、適宜読み替えてください。
一時保存だから、一般には公開したくないわけで、postsテーブルにpublishedを追加して、create_tempアクションでは publish=false としています。
  
config/routesはこんな感じ。


resources :posts
post '/posts/temp',   to: 'posts#create_temp',  as: :temp_post

  

###Javascriptでフォーム送信


ready = ->
	# Temporal Saving
	if $('.create-temp')
		window.tempTimer = null
		$('.blog-form form').keydown ->
			# reset
			window.clearTimeout(tempTimer)
			window.tempTimer = window.setTimeout ->
				tempSubmit()
			, 5000

tempSubmit = ->
	# create
	if $('.create-temp span').data('result') != true
		$(".blog-form").ajaxSubmit(
			url: '/posts/temp',
			type: 'post'
		)
	# update
	else
		$(".blog-form form").ajaxSubmit()

# For turbolinks
$(document).ready(ready)
$(document).on('page:load', ready)

  
色んなやり方があると思いますが、keydownされた後、5秒たったら一時保存のフォーム送信をするようにしました。
5秒以内にkeydownされると、キャンセルされます。

ユーザーのアクション関係なくデータを投げるのもありかもしれませんが、ユーザーが画面を開きっぱなしでどこかに行ってしまったら、ずーーっと送信されることになります…ので、なにか手は必要ですね。
ajax送信にはこのプラグインを使いました。
  
Turbolinksなので、page:loadを使わないとダメです。
  

###Viewファイル

jsに対応するビューファイルを作ります。


var result = <%= @post.valid? %>;
var msg = "";
var notice = "";

if (result == true) {
	msg = "下書き保存されました";

	// This is for Temporal saving
	// forcing the form to look update method.

	// Add id
	$('.blog-form').prepend('<input name="post[id]" type="hidden" value="<%= @post.id %>">');

	// Chnage REST method
	$('.blog-form input[name=_method]').remove();
	$('.blog-form').prepend('<input name="_method" type="hidden" value="patch">');

	// Change URL
	$('.blog-form').attr('action', '/posts/<%= @post.id %>');

} else {
	msg = "下書き保存のための情報が足りません";
}


// Message
notice = "<span data-result=" + result + ">" + msg + "</span>";
$('.create-temp span').remove();
$('.create-temp').hide().append(notice).fadeIn();

  
一回目の一時保存は普通にcreate_tempアクションに飛んでもらって良いんだけど、次のタイミング(例えば1分に1回保存するとかする場合)では、もうそのレコードはあるんだから、updateアクションに飛んでもらわないと困る。
  
ということで、javascriptでフォームの内容を変更しています。
強引だけど、これ以外に思いつかなかった。

Railsのフォームは input name="_method" で、フォームの送信先を変える情報を持っています。
同じPOST送信でも、value="patch"ならupdateメソッド、value="post"ならcreateメソッドが呼び出されるので、updateしたいタイミングで変更してるのです。
  

###updateメソッド

最後にupdateメソッド。
通常のupdateと、一時保存のupdateで、publishedの状態を変える必要があります。

通常update(送信ボタンを押した時)
published = true

一時保存update(下書きとして扱う)
published = false

あと、通常はHTML、一時保存はajaxなので、respond_toで分けています。
こんな感じになりました。


	def update
		# 所有権のチェック
		@post.attributes = strong_params
		# publish if update botton was clicked
		@post.published = true if params[:commit]

		respond_to do |format|
			format.js do
				@post.save
			end
			format.html do
				if @post.save
					flash[:success] = "ブログが更新されました。"
					redirect_to @post
				else
					render 'edit'
				end
			end
		end
	end

  
updateの前にこの記事が本当にユーザーの持ち物かどうかチェックする必要がありますが(所有権のチェック)、そのメソッドは省略します。
  
以上です。
初めてやってみたので、つっこみあればお願いします :)

http://workabroad.jp/posts/2091

9
8
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
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?