SlideShare une entreprise Scribd logo
1  sur  33
Télécharger pour lire hors ligne
Ajax nested form &
Ajax upload in Rails
   何澤清 Tse-Ching Ho
     2012/08/21
About


• https://github.com/tsechingho
• https://twitter.com/tsechingho
• https://facebook.com/tsechingho
Demo Code
https://github.com/tsechingho/ajax-tutorial
Prerequisite Work
Gems supposed to
        be well understood

• jquery-rails
• anjlab-bootstrap-rails
• simple_form
• carrierwave
• mini_magick / rmagick
Ground rails project

• Have two models associated with has_many
• Have one model mounted with carrierwave’s
 uploader

• Render 'form' in views of new and edit
• Use respond_with for each action of controller
• Layout with twitter bootstrap
Twitter Bootstrap Modal
Handle Feedback
of .ajaxSubmit() via Modal


   modal    modal       modal      modal




                        Error
                       feedback    Success
           .feedback
                         modal    feedback
Creature & CreaturePhoto

                                                       require 'file_size_validator'

                                                       class CreaturePhoto < ActiveRecord::Base
class Creature < ActiveRecord::Base
                                                         attr_accessible :content_type, :file_name, :file_size,
 attr_accessible :characteristic, :place_of_origin,
                                                       :creature_id, :source, :source_cache, :remove_source
:popular_name, :scientific_name, :animal_handbook_ids
                                                        validates :source,
 validates :popular_name, presence: true
                                                         file_size: {
                                                           maximum: 3.megabytes.to_i
 has_many :animal_handbook_creatures
                                                         }
 has_many :animal_handbooks,
through: :animal_handbook_creatures
                                                        mount_uploader :source,
 has_many :photos, class_name: 'CreaturePhoto'
                                                       CreaturePhotoUploader, mount_on: :file_name
                                                        delegate :url, :current_path, :size, :filename, to: :source
 def name
  popular_name
                                                        belongs_to :creature
 end
end
                                                        before_save :update_attributes_with_source
                                                       end
creatures_controller.rb
class CreaturesController < ApplicationController
 before_filter :load_creature, only: [:show, :edit, :update, :destroy]

 respond_to :html

 def edit
  render 'edit_modal', layout: false if request.xhr?
 end

 def update
  @creature.update_attributes params[:creature]
  if @creature.valid?
    flash[:notice] = 'Creature was successfully updated.'
  end
  respond_with @creature do |format|
    format.html {
      if @creature.valid?
        load_creatures
        render partial: 'table', locals: { creatures: @creatures }
      else
        render 'edit_modal', layout: false
      end
    } if request.xhr?
  end
  flash.discard :notice if request.xhr?
 end
end
twitter_bootstrap_helper.rb
def iconed_link_to(text, url, options = {})
 icon_class = options.delete(:icon_class)
 link_to url, options do
   content_tag(:i, nil, class: icon_class) << ' ' << text
 end
end

def link_to_edit(url, options = {})
 icon_class = options.delete(:icon_class) || 'icon-edit'
 default_options = { title: t('helpers.edit'), class: 'btn', icon_class: icon_class }
 iconed_link_to nil, url, default_options.deep_merge(options)
end

def link_to_edit_modal(url, modal_id)
 default_options = { remote: true, data: { target: modal_id, toggle: 'modal', type:
'html' }, class: 'btn modal-open' }
 link_to_edit url, default_options
end
creatures/index.html.erb
<article id="creature-list">
 <header>
  <h1><%= t('.title') %></h1>
 </header>

 <%= render_list class: 'nav nav-tabs' do |li|
  li << [link_to_open_modal(t('helpers.new'), new_creature_path, '#creature-
modal'), { class: 'action' }]
 end %>

 <%= render 'table', creatures: @creatures %>

 <nav role="pagination">
 </nav>
</article>

<div class="modal hide fade" id="creature-modal"></div>
creatures/_table.html.erb
<table class="table table-striped table-bordered">
 <tr>
   <th><%= Creature.human_attribute_name :popular_name %></th>
   <th><%= Creature.human_attribute_name :scientific_name %></th>
   <th><%= Creature.human_attribute_name :place_of_origin %></th>
   <th><%= Creature.human_attribute_name :characteristic %></th>
   <th><%= t('helpers.actions') %></th>
 </tr>
 <% creatures.each do |creature| %>
   <tr>
    <td><%= creature.popular_name %></td>
    <td><%= creature.scientific_name %></td>
    <td><%= creature.place_of_origin %></td>
    <td><%= creature.characteristic %></td>
    <td class="btn-group">
      <%= link_to_show creature_path(creature) %>
      <%= link_to_edit_modal edit_creature_path(creature), '#creature-modal' %>
      <%= link_to_destroy creature_path(creature) %>
    </td>
   </tr>
 <% end %>
</table>
creatures/edit_modal.html.erb
<%= simple_form_for @creature, remote: true, html: { data: { type: 'html' }, class:
'form-horizontal' } do |f| %>
  <div class="modal-header">
   <button type="button" class="close" data-dismiss="modal">×</button>
   <h3><%= t('.title') %></h3>
  </div>

 <div class="modal-body">
  <%= render 'form', f: f %>
 </div>

 <div class="modal-footer">
  <a href="#" class="btn" data-dismiss="modal"><%= t('helpers.close') %></a>
  <%= f.button :submit, name: nil, class: 'btn-primary' %>
 </div>
<% end %>
modal.js.coffee
$ ->
 $.modal ||= {}

 $.modal.appendFeedback = (modal, data) ->
  $('<div>').addClass('feedback hide').html(data).appendTo(modal)

 $.modal.replaceFeedback = (modal) ->
  modal.html(modal.children('.feedback').html())
  $.modal.enableChosen()

 $.modal.replaceTable = (table_id, modal = $(this)) ->
  feedback_table = modal.find('.table')
  table = $(table_id).find('.table')
  table.html(feedback_table.html())
  modal.find('.feedback').remove().end()
     .modal('hide')
  table.effect('shake')
  return true
creatures.js.coffee
$ ->
 $('#creature-list')
   .on 'ajax:success', 'a.modal-open', (event, data, status, xhr) ->
    modal = $($(this).attr('data-target'))
    modal.html(data)
    $.modal.enableChosen()
   .on 'ajax:error', '.a.modal-open', (event, xhr, status, error) ->
    modal = $($(this).attr('data-target'))
    $.modal.showErrorModal(status, error, modal)

 $('#creature-modal')
  .on 'ajax:success', '.simple_form', (event, data, status, xhr) ->
   modal = $(this).parent()
   $.modal.appendFeedback(modal, data)
   if modal.find('.feedback .alert-error').size() > 0
     $.modal.replaceFeedback(modal)
     return true
   table_id = '#creature-list'
   $.modal.replaceTable(table_id, modal)
  .on 'ajax:error', '.simple_form', (event, xhr, status, error) ->
   modal = $('#creature-modal')
   $.modal.showErrorModal(status, error, modal)
application.js

//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require bootstrap
//= require chosen-jquery
//= require modal
//= require_tree .
Key Points
• Use respond_with
• Render 'modal' specific files
• Render partial files
• Via data attributes
• Define rails ajax callbacks
• Use namespace for javascript methods
• Catch ajax callback in div container if data-type
  is :html
Ajax Nested Form
How To

• Concepts
  • Save template in data attributes
  • DOM manipulation
• https://github.com/nathanvda/cocoon
• gem 'cocoon'
creature.rb
class Creature < ActiveRecord::Base
  attr_accessible :characteristic, :place_of_origin, :popular_name, :scientific_name,
:animal_handbook_ids, :photos_attributes

 validates :popular_name, presence: true

 has_many :animal_handbook_creatures
 has_many :animal_handbooks, through: :animal_handbook_creatures
 has_many :photos, class_name: 'CreaturePhoto'
 accepts_nested_attributes_for :photos, allow_destroy: true, reject_if: proc
{ |obj| obj.blank? }

 def name
  popular_name
 end
end
twitter_bootstrap_helper.rb
module TwitterBootstrapHelper
 def iconed_link_to_add_association(text, *args)
  args << {} if args.size < 2
  icon_class = args.last.delete(:icon_class) || 'icon-plus'
  default_options = { title: t('helpers.add'), class: 'btn' }
  args.last.deep_merge! default_options
  link_to_add_association *args do
    content_tag(:i, nil, class: icon_class) << ' ' << text
  end
 end

 def iconed_link_to_remove_association(text, *args)
  args << {} if args.size < 2
  icon_class = args.last.delete(:icon_class) || 'icon-remove'
  default_options = { title: t('helpers.remove'), class: 'btn' }
  args.last.deep_merge! default_options
  link_to_remove_association *args do
    content_tag(:i, nil, class: icon_class) << ' ' << text
  end
 end
end
creatures/_form.html.erb
<%= f.error_notification %>

<div class="form-inputs">
 <%= f.input :popular_name %>
 <%= f.input :scientific_name %>
 <%= f.input :place_of_origin %>
 <%= f.input :characteristic, input_html: { size: '20x5' } %>
 <%= f.association :animal_handbooks, input_html: { class: 'chzn-select' } %>
</div>


<h3><%= t('.creature_photos') %></h3>
<div class="form-inputs form-inline">
 <%= render 'creature_photos/field_labels', creature_form: f %>
 <%= f.simple_fields_for :photos do |f2| %>
  <%= render 'creature_photos/fields', f: f2 %>
 <% end %>
</div>

<%= iconed_link_to_add_association t('helpers.add'),
 f,
 :photos,
 data: {
  :'association-insertion-node' => '.form-inputs.form-inline',
  :'association-insertion-method' => :append
 },
 partial: 'creature_photos/fields',
 render_options: {
  locals: { }
 } %>
creatures/_fields.html.erb


<%= field_set_tag nil, class: 'creature-fields row-fluid nested-form-hidden-label nested-fields' do %>
 <%= f.input :popular_name, wrapper_html: { class: 'span2' }, input_html: { class: 'span12' } %>
 <%= f.input :scientific_name, wrapper_html: { class: 'span2' }, input_html: { class: 'span12' } %>
 <%= f.input :place_of_origin, wrapper_html: { class: 'span2' }, input_html: { class: 'span12' } %>
 <%= f.input :characteristic, as: :string, wrapper_html: { class: 'span4' }, input_html: { class: 'span12' } %>
 <div class="control-group actions span2">
  <%= iconed_link_to_remove_association nil, f %>
 </div>
<% end %>
application.js

//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require bootstrap
//= require chosen-jquery
//= require cocoon
//= require modal
//= require_tree .
Key Points
• accepts_nested_attributes_for :photos, allow_destroy:
  true

• attr_accessible :photos_attributes
• Render partial file
• Use link_to_add_association helper
• Use link_to_remove_association helper
• Add 'nested-fields' class to container tag of nested item
• Require cocoon javascript
Ajax Upload
               It’s impossible
since browsers forbid for security reason.
    It’s possible if we cheat browsers.
How To

• Concepts
  • iFrame Transport
  • rack middleware to modify request header
• https://github.com/leppert/remotipart
• gem 'remotipart'
iFrame Transport
http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/
application.js

//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require bootstrap
//= require chosen-jquery
//= require cocoon
// Since XMLHttpRequest (AJAX) standard has no support for file uploads,
// use iframe-transport method of remotipart gem for ajax file upload.
//= require jquery.remotipart
//= require modal
//= require_tree .
Other ways?
• iFrame
  • https://github.com/blueimp/jQuery-File-Upload
• Flash
  • http://www.uploadify.com
• Form Data
  • http://hacks.mozilla.org/2010/07/firefox-4-
    formdata-and-the-new-file-url-object/
References
•   http://www.alfajango.com/blog/rails-3-remote-links-
    and-forms/

•   http://www.alfajango.com/blog/rails-3-remote-links-
    and-forms-data-type-with-jquery/

•   http://railscasts.com/episodes/196-nested-model-
    form-revised

•   http://www.alfajango.com/blog/ajax-file-uploads-with-
    the-iframe-method/

•   http://os.alfajango.com/remotipart/
THANKS

Contenu connexe

Tendances

Aristotle Poetics concepts of Tragedy and Plot
Aristotle Poetics concepts of Tragedy and PlotAristotle Poetics concepts of Tragedy and Plot
Aristotle Poetics concepts of Tragedy and PlotAleeenaFarooq
 
Aristotle's Poetics
Aristotle's PoeticsAristotle's Poetics
Aristotle's PoeticsMann Rentoy
 
Wordsworth's theory of poetic diction
Wordsworth's theory of poetic dictionWordsworth's theory of poetic diction
Wordsworth's theory of poetic dictionjyotiba gohil
 
Tradition and individual talent
Tradition and individual talentTradition and individual talent
Tradition and individual talentMustheena k
 
The Rime Of The Ancient Mariner
The Rime Of The Ancient Mariner The Rime Of The Ancient Mariner
The Rime Of The Ancient Mariner Jayita Sanapathi
 
analysis of Robinson Crusoe's dream.
analysis of Robinson Crusoe's dream. analysis of Robinson Crusoe's dream.
analysis of Robinson Crusoe's dream. Parmar Milan
 
Character Of Victor Frankenstein
Character Of Victor Frankenstein Character Of Victor Frankenstein
Character Of Victor Frankenstein NikitaRathod20
 
Biography literaria chapter 18
Biography literaria chapter 18Biography literaria chapter 18
Biography literaria chapter 18Anamta Dua
 
Arnold and his criticism [The Study of Poetry]
Arnold and his criticism [The Study of Poetry]Arnold and his criticism [The Study of Poetry]
Arnold and his criticism [The Study of Poetry]Iffat Jahan Suchona
 
Dante Gabriel Rossetti - painter and poet
Dante Gabriel Rossetti  -   painter and poetDante Gabriel Rossetti  -   painter and poet
Dante Gabriel Rossetti - painter and poetElizabeth Bertell
 
Neoclassical age an age of satire
Neoclassical age   an age of satireNeoclassical age   an age of satire
Neoclassical age an age of satireAjit Kaliya
 
Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.
Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.
Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.Department of English
 
Troy Town And Neutral Tones
Troy Town And Neutral TonesTroy Town And Neutral Tones
Troy Town And Neutral TonesLetra Essencia
 
Ode to nightingale
Ode to nightingaleOde to nightingale
Ode to nightingaleera nauman
 
Thematic concern of the old man and the sea
Thematic concern of the old man and the seaThematic concern of the old man and the sea
Thematic concern of the old man and the seaHitesh Galthariya
 
Willing suspension of disbelief by samuel taylor coleridge
Willing suspension of disbelief by samuel taylor coleridgeWilling suspension of disbelief by samuel taylor coleridge
Willing suspension of disbelief by samuel taylor coleridgeDayamani Surya
 

Tendances (20)

Aristotle Poetics concepts of Tragedy and Plot
Aristotle Poetics concepts of Tragedy and PlotAristotle Poetics concepts of Tragedy and Plot
Aristotle Poetics concepts of Tragedy and Plot
 
Aristotle's Poetics
Aristotle's PoeticsAristotle's Poetics
Aristotle's Poetics
 
Wordsworth's theory of poetic diction
Wordsworth's theory of poetic dictionWordsworth's theory of poetic diction
Wordsworth's theory of poetic diction
 
Tradition and individual talent
Tradition and individual talentTradition and individual talent
Tradition and individual talent
 
The Rime Of The Ancient Mariner
The Rime Of The Ancient Mariner The Rime Of The Ancient Mariner
The Rime Of The Ancient Mariner
 
The gudie
The gudieThe gudie
The gudie
 
Lucy poems
Lucy poemsLucy poems
Lucy poems
 
A nice cup of tea.
A nice cup of tea.A nice cup of tea.
A nice cup of tea.
 
Preface to shakespeare
Preface to shakespearePreface to shakespeare
Preface to shakespeare
 
analysis of Robinson Crusoe's dream.
analysis of Robinson Crusoe's dream. analysis of Robinson Crusoe's dream.
analysis of Robinson Crusoe's dream.
 
Character Of Victor Frankenstein
Character Of Victor Frankenstein Character Of Victor Frankenstein
Character Of Victor Frankenstein
 
Biography literaria chapter 18
Biography literaria chapter 18Biography literaria chapter 18
Biography literaria chapter 18
 
Arnold and his criticism [The Study of Poetry]
Arnold and his criticism [The Study of Poetry]Arnold and his criticism [The Study of Poetry]
Arnold and his criticism [The Study of Poetry]
 
Dante Gabriel Rossetti - painter and poet
Dante Gabriel Rossetti  -   painter and poetDante Gabriel Rossetti  -   painter and poet
Dante Gabriel Rossetti - painter and poet
 
Neoclassical age an age of satire
Neoclassical age   an age of satireNeoclassical age   an age of satire
Neoclassical age an age of satire
 
Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.
Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.
Character sketch of 'Datta' in "The Gold Frame" by R.K.Laxman.
 
Troy Town And Neutral Tones
Troy Town And Neutral TonesTroy Town And Neutral Tones
Troy Town And Neutral Tones
 
Ode to nightingale
Ode to nightingaleOde to nightingale
Ode to nightingale
 
Thematic concern of the old man and the sea
Thematic concern of the old man and the seaThematic concern of the old man and the sea
Thematic concern of the old man and the sea
 
Willing suspension of disbelief by samuel taylor coleridge
Willing suspension of disbelief by samuel taylor coleridgeWilling suspension of disbelief by samuel taylor coleridge
Willing suspension of disbelief by samuel taylor coleridge
 

Similaire à Ajax nested form and ajax upload in rails

Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Luka Zakrajšek
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)tompunk
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneRafael Felix da Silva
 
PHPConf-TW 2012 # Twig
PHPConf-TW 2012 # TwigPHPConf-TW 2012 # Twig
PHPConf-TW 2012 # TwigWake Liu
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoMohamed Mosaad
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3giwoolee
 
Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2RORLAB
 
WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3Mizanur Rahaman Mizan
 
اسلاید جلسه ۹ کلاس پایتون برای هکر های قانونی
اسلاید جلسه ۹ کلاس پایتون برای هکر های قانونیاسلاید جلسه ۹ کلاس پایتون برای هکر های قانونی
اسلاید جلسه ۹ کلاس پایتون برای هکر های قانونیMohammad Reza Kamalifard
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialYi-Ting Cheng
 
Slimme Joomla! Templating Tips en Truuks
Slimme Joomla! Templating Tips en TruuksSlimme Joomla! Templating Tips en Truuks
Slimme Joomla! Templating Tips en TruuksThemePartner
 

Similaire à Ajax nested form and ajax upload in rails (20)

Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
 
PHPConf-TW 2012 # Twig
PHPConf-TW 2012 # TwigPHPConf-TW 2012 # Twig
PHPConf-TW 2012 # Twig
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup Cairo
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
 
Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Flask – Python
Flask – PythonFlask – Python
Flask – Python
 
WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3
 
اسلاید جلسه ۹ کلاس پایتون برای هکر های قانونی
اسلاید جلسه ۹ کلاس پایتون برای هکر های قانونیاسلاید جلسه ۹ کلاس پایتون برای هکر های قانونی
اسلاید جلسه ۹ کلاس پایتون برای هکر های قانونی
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Slimme Joomla! Templating Tips en Truuks
Slimme Joomla! Templating Tips en TruuksSlimme Joomla! Templating Tips en Truuks
Slimme Joomla! Templating Tips en Truuks
 

Plus de Tse-Ching Ho

20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_twTse-Ching Ho
 
Ruby on bioinformatics
Ruby on bioinformaticsRuby on bioinformatics
Ruby on bioinformaticsTse-Ching Ho
 
mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introductionTse-Ching Ho
 
devise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwandevise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwanTse-Ching Ho
 
Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817Tse-Ching Ho
 
model.search: customize your own search logic
model.search: customize your own search logicmodel.search: customize your own search logic
model.search: customize your own search logicTse-Ching Ho
 
The Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesThe Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesTse-Ching Ho
 

Plus de Tse-Ching Ho (9)

20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_tw
 
Ruby on bioinformatics
Ruby on bioinformaticsRuby on bioinformatics
Ruby on bioinformatics
 
Webconf2013
Webconf2013Webconf2013
Webconf2013
 
mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introduction
 
devise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwandevise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwan
 
Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817
 
model.search: customize your own search logic
model.search: customize your own search logicmodel.search: customize your own search logic
model.search: customize your own search logic
 
The Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesThe Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & Templates
 
ruby e-commerce
ruby e-commerceruby e-commerce
ruby e-commerce
 

Dernier

Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 

Dernier (20)

Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 

Ajax nested form and ajax upload in rails

  • 1. Ajax nested form & Ajax upload in Rails 何澤清 Tse-Ching Ho 2012/08/21
  • 5. Gems supposed to be well understood • jquery-rails • anjlab-bootstrap-rails • simple_form • carrierwave • mini_magick / rmagick
  • 6. Ground rails project • Have two models associated with has_many • Have one model mounted with carrierwave’s uploader • Render 'form' in views of new and edit • Use respond_with for each action of controller • Layout with twitter bootstrap
  • 8. Handle Feedback of .ajaxSubmit() via Modal modal modal modal modal Error feedback Success .feedback modal feedback
  • 9. Creature & CreaturePhoto require 'file_size_validator' class CreaturePhoto < ActiveRecord::Base class Creature < ActiveRecord::Base attr_accessible :content_type, :file_name, :file_size, attr_accessible :characteristic, :place_of_origin, :creature_id, :source, :source_cache, :remove_source :popular_name, :scientific_name, :animal_handbook_ids validates :source, validates :popular_name, presence: true file_size: { maximum: 3.megabytes.to_i has_many :animal_handbook_creatures } has_many :animal_handbooks, through: :animal_handbook_creatures mount_uploader :source, has_many :photos, class_name: 'CreaturePhoto' CreaturePhotoUploader, mount_on: :file_name delegate :url, :current_path, :size, :filename, to: :source def name popular_name belongs_to :creature end end before_save :update_attributes_with_source end
  • 10. creatures_controller.rb class CreaturesController < ApplicationController before_filter :load_creature, only: [:show, :edit, :update, :destroy] respond_to :html def edit render 'edit_modal', layout: false if request.xhr? end def update @creature.update_attributes params[:creature] if @creature.valid? flash[:notice] = 'Creature was successfully updated.' end respond_with @creature do |format| format.html { if @creature.valid? load_creatures render partial: 'table', locals: { creatures: @creatures } else render 'edit_modal', layout: false end } if request.xhr? end flash.discard :notice if request.xhr? end end
  • 11. twitter_bootstrap_helper.rb def iconed_link_to(text, url, options = {}) icon_class = options.delete(:icon_class) link_to url, options do content_tag(:i, nil, class: icon_class) << ' ' << text end end def link_to_edit(url, options = {}) icon_class = options.delete(:icon_class) || 'icon-edit' default_options = { title: t('helpers.edit'), class: 'btn', icon_class: icon_class } iconed_link_to nil, url, default_options.deep_merge(options) end def link_to_edit_modal(url, modal_id) default_options = { remote: true, data: { target: modal_id, toggle: 'modal', type: 'html' }, class: 'btn modal-open' } link_to_edit url, default_options end
  • 12. creatures/index.html.erb <article id="creature-list"> <header> <h1><%= t('.title') %></h1> </header> <%= render_list class: 'nav nav-tabs' do |li| li << [link_to_open_modal(t('helpers.new'), new_creature_path, '#creature- modal'), { class: 'action' }] end %> <%= render 'table', creatures: @creatures %> <nav role="pagination"> </nav> </article> <div class="modal hide fade" id="creature-modal"></div>
  • 13. creatures/_table.html.erb <table class="table table-striped table-bordered"> <tr> <th><%= Creature.human_attribute_name :popular_name %></th> <th><%= Creature.human_attribute_name :scientific_name %></th> <th><%= Creature.human_attribute_name :place_of_origin %></th> <th><%= Creature.human_attribute_name :characteristic %></th> <th><%= t('helpers.actions') %></th> </tr> <% creatures.each do |creature| %> <tr> <td><%= creature.popular_name %></td> <td><%= creature.scientific_name %></td> <td><%= creature.place_of_origin %></td> <td><%= creature.characteristic %></td> <td class="btn-group"> <%= link_to_show creature_path(creature) %> <%= link_to_edit_modal edit_creature_path(creature), '#creature-modal' %> <%= link_to_destroy creature_path(creature) %> </td> </tr> <% end %> </table>
  • 14. creatures/edit_modal.html.erb <%= simple_form_for @creature, remote: true, html: { data: { type: 'html' }, class: 'form-horizontal' } do |f| %> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h3><%= t('.title') %></h3> </div> <div class="modal-body"> <%= render 'form', f: f %> </div> <div class="modal-footer"> <a href="#" class="btn" data-dismiss="modal"><%= t('helpers.close') %></a> <%= f.button :submit, name: nil, class: 'btn-primary' %> </div> <% end %>
  • 15. modal.js.coffee $ -> $.modal ||= {} $.modal.appendFeedback = (modal, data) -> $('<div>').addClass('feedback hide').html(data).appendTo(modal) $.modal.replaceFeedback = (modal) -> modal.html(modal.children('.feedback').html()) $.modal.enableChosen() $.modal.replaceTable = (table_id, modal = $(this)) -> feedback_table = modal.find('.table') table = $(table_id).find('.table') table.html(feedback_table.html()) modal.find('.feedback').remove().end() .modal('hide') table.effect('shake') return true
  • 16. creatures.js.coffee $ -> $('#creature-list') .on 'ajax:success', 'a.modal-open', (event, data, status, xhr) -> modal = $($(this).attr('data-target')) modal.html(data) $.modal.enableChosen() .on 'ajax:error', '.a.modal-open', (event, xhr, status, error) -> modal = $($(this).attr('data-target')) $.modal.showErrorModal(status, error, modal) $('#creature-modal') .on 'ajax:success', '.simple_form', (event, data, status, xhr) -> modal = $(this).parent() $.modal.appendFeedback(modal, data) if modal.find('.feedback .alert-error').size() > 0 $.modal.replaceFeedback(modal) return true table_id = '#creature-list' $.modal.replaceTable(table_id, modal) .on 'ajax:error', '.simple_form', (event, xhr, status, error) -> modal = $('#creature-modal') $.modal.showErrorModal(status, error, modal)
  • 17. application.js //= require jquery //= require jquery-ui //= require jquery_ujs //= require bootstrap //= require chosen-jquery //= require modal //= require_tree .
  • 18. Key Points • Use respond_with • Render 'modal' specific files • Render partial files • Via data attributes • Define rails ajax callbacks • Use namespace for javascript methods • Catch ajax callback in div container if data-type is :html
  • 20. How To • Concepts • Save template in data attributes • DOM manipulation • https://github.com/nathanvda/cocoon • gem 'cocoon'
  • 21. creature.rb class Creature < ActiveRecord::Base attr_accessible :characteristic, :place_of_origin, :popular_name, :scientific_name, :animal_handbook_ids, :photos_attributes validates :popular_name, presence: true has_many :animal_handbook_creatures has_many :animal_handbooks, through: :animal_handbook_creatures has_many :photos, class_name: 'CreaturePhoto' accepts_nested_attributes_for :photos, allow_destroy: true, reject_if: proc { |obj| obj.blank? } def name popular_name end end
  • 22. twitter_bootstrap_helper.rb module TwitterBootstrapHelper def iconed_link_to_add_association(text, *args) args << {} if args.size < 2 icon_class = args.last.delete(:icon_class) || 'icon-plus' default_options = { title: t('helpers.add'), class: 'btn' } args.last.deep_merge! default_options link_to_add_association *args do content_tag(:i, nil, class: icon_class) << ' ' << text end end def iconed_link_to_remove_association(text, *args) args << {} if args.size < 2 icon_class = args.last.delete(:icon_class) || 'icon-remove' default_options = { title: t('helpers.remove'), class: 'btn' } args.last.deep_merge! default_options link_to_remove_association *args do content_tag(:i, nil, class: icon_class) << ' ' << text end end end
  • 23. creatures/_form.html.erb <%= f.error_notification %> <div class="form-inputs"> <%= f.input :popular_name %> <%= f.input :scientific_name %> <%= f.input :place_of_origin %> <%= f.input :characteristic, input_html: { size: '20x5' } %> <%= f.association :animal_handbooks, input_html: { class: 'chzn-select' } %> </div> <h3><%= t('.creature_photos') %></h3> <div class="form-inputs form-inline"> <%= render 'creature_photos/field_labels', creature_form: f %> <%= f.simple_fields_for :photos do |f2| %> <%= render 'creature_photos/fields', f: f2 %> <% end %> </div> <%= iconed_link_to_add_association t('helpers.add'), f, :photos, data: { :'association-insertion-node' => '.form-inputs.form-inline', :'association-insertion-method' => :append }, partial: 'creature_photos/fields', render_options: { locals: { } } %>
  • 24. creatures/_fields.html.erb <%= field_set_tag nil, class: 'creature-fields row-fluid nested-form-hidden-label nested-fields' do %> <%= f.input :popular_name, wrapper_html: { class: 'span2' }, input_html: { class: 'span12' } %> <%= f.input :scientific_name, wrapper_html: { class: 'span2' }, input_html: { class: 'span12' } %> <%= f.input :place_of_origin, wrapper_html: { class: 'span2' }, input_html: { class: 'span12' } %> <%= f.input :characteristic, as: :string, wrapper_html: { class: 'span4' }, input_html: { class: 'span12' } %> <div class="control-group actions span2"> <%= iconed_link_to_remove_association nil, f %> </div> <% end %>
  • 25. application.js //= require jquery //= require jquery-ui //= require jquery_ujs //= require bootstrap //= require chosen-jquery //= require cocoon //= require modal //= require_tree .
  • 26. Key Points • accepts_nested_attributes_for :photos, allow_destroy: true • attr_accessible :photos_attributes • Render partial file • Use link_to_add_association helper • Use link_to_remove_association helper • Add 'nested-fields' class to container tag of nested item • Require cocoon javascript
  • 27. Ajax Upload It’s impossible since browsers forbid for security reason. It’s possible if we cheat browsers.
  • 28. How To • Concepts • iFrame Transport • rack middleware to modify request header • https://github.com/leppert/remotipart • gem 'remotipart'
  • 30. application.js //= require jquery //= require jquery-ui //= require jquery_ujs //= require bootstrap //= require chosen-jquery //= require cocoon // Since XMLHttpRequest (AJAX) standard has no support for file uploads, // use iframe-transport method of remotipart gem for ajax file upload. //= require jquery.remotipart //= require modal //= require_tree .
  • 31. Other ways? • iFrame • https://github.com/blueimp/jQuery-File-Upload • Flash • http://www.uploadify.com • Form Data • http://hacks.mozilla.org/2010/07/firefox-4- formdata-and-the-new-file-url-object/
  • 32. References • http://www.alfajango.com/blog/rails-3-remote-links- and-forms/ • http://www.alfajango.com/blog/rails-3-remote-links- and-forms-data-type-with-jquery/ • http://railscasts.com/episodes/196-nested-model- form-revised • http://www.alfajango.com/blog/ajax-file-uploads-with- the-iframe-method/ • http://os.alfajango.com/remotipart/