元々のフォームはsubmitしたくない。フロントとかサーバーとかで二重送信防止してたりすると、previewしたら二度とsubmitできないみたいな感じになってしまうと思う。
form内にリンク置いといて、それクリックしたらフォームをcloneして、actionだけ変えてsubmitするというのはまあまあ汎用的に使えて良いのではないかという風に思いついて書いてみた。
# config/routes.rb
resources :posts
collection do
post :preview
end
end
# app/controllers/posts_controller.rb
def preview
@post = Post.new(post_params)
render :show
end
private
def post_params
params.require(:posts).permit(:title, :body)
end
# app/view/posts/new.html.erb
<%= form_for(@post) do |p| %>
<%= p.text_field :title %>
<%= p.text_area :body %>
<%= link_to('Preview', preview_posts_path, :class => 'preview_btn') %>
<%= p.submit :disable_with => 'Sending...' %>
<% end%>
# app/assets/javascript/posts.js.coffee
$ ->
$preview_btn = $ '.preview_btn'
$preview_btn.on 'click', (evt)->
evt.preventDefault()
$target = $ evt.target
$form = $target.closest('form')
# こうしないと謎にtextareaのvalueがcloneされない
$form.find('textarea').each (index, node)->
$node = $ node
$node.text $node.val()
$preview_form = $form.clone().hide().attr({
action: $target.attr('href'),
target: '_blank'
})
# edit時とかだと <input name="_method"> のvalueがputになっている
$preview_form.find('[name=_method]').val 'post'
$('body').append $preview_form
$preview_form.submit()
$preview_form.remove()
$preview_form = null