LoginSignup
9
8

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