kame's engineer note

技術関連のメモをブログに記録していく

Rails ajaxでhogehoge.js.slim(erb)を使わずにHTMLを書き換える

概要

前回の記事では、ajaxを実現するためのファイル構成は以下のようになっていた。

- controllers
  - photo_controller.rb
- views
  - photo
    - new.html.slim
    - new.js.slim
    - _add_photo_form.html.slim

例えばviews内にjsファイルを配置するのではなく、なるべくassets内のjsファイルにまとめて記述したほうがシンプルで良いという場合があると思う。 今回は、このajaxアクションのために必要なnews.js.slimをなくしてajaxを行う方法を書いてみる。

今回のファイル構成は以下のようになる。

- controllers
  - photo_controller.rb
- views
  - photo
    - new.html.slim
    - \_add_photo_form.html.slim
- assets
  - javascript
    - photo.js.coffee

viewファイル

viewファイルは前回とほとんど同じ。

new.html.slim

#選択したファイルのプレビューを表示
javascript:
  function readUploadImage(input) {
    if (input.files && input.files[0]) {
      var reader = new FileReader();
      reader.onload = function (e) {
        $(input).next()
          .attr('src', e.target.result)
          .width(100);
      };
      reader.readAsDataURL(input.files[0]);
    }
  }

div
  = form_for(@user, url: form_path, html: {multipart: true}) do |f|
    .div
      =link_to 'ボタンを追加する', new_path(@user.id),remote: true,data: {role: 'add_input'}
    .div data-role="photo_area"
      - @user.photos.each do |p|
        .div
          = image_tag p.image.url(:thumb)
          = check_box 'delete',"#{p.id}"
          = label_tag "delete[#{p.id}]", '削除'
      = render partial: 'photo_upload'
    .div
      = f.submit "登録する"

_add_photo_form.html.slim

.div
  = fields_for "user[photos_attributes][#{Time.now.to_i}]" do |ff|
    = ff.file_field :image, onchange: "readUploadImage(this)"
    = image_tag ''

render json(or text) でhtmlコンテンツを返す

photo_controller.rb

def new
  if request.xhr?
    content = render_to_string(:partial => 'add_photo_form')
    render json: {html: content}, status: :ok
  end
end

ajax通信があった場合、まずはrender_to_stringで読み込みたいviewファイルをstring化する。 それをjson形式で返してあげる。(textでも可)

photo.js.coffee

$(window).on 'load' ,->
  $('[data-role="add_input"]').bind 'ajax:beforeSend', () ->
    console.log 'start'
  .bind 'ajax:complete',(e,data,status,xhr) ->
    if data.responseJSON?
      $('[data-role="photo_area"]').append data.responseJSON.html

javascriptajaxのcallbackを使って、上記のcontroller側から返したjsonデータを取得し、指定の箇所にappendする。

以上で終わり。