SlideShare a Scribd company logo
A Better UJS for Rails
Codemy.net
presents
@zacksiriby:
Monday, June 10, 13
Javascript is a big part of Rails Project
Monday, June 10, 13
No real convention for
working with JS files
Monday, June 10, 13
Backbone is Great but...
Monday, June 10, 13
I miss working with Ruby
Monday, June 10, 13
And then I saw Turbolinks...
Monday, June 10, 13
Monday, June 10, 13
Turbolinks Backbone / MV*
Control / Complexity for Client
Less Ruby
Monday, June 10, 13
So I thought long and hard
Monday, June 10, 13
Turbolinks Backbone / MV*
?
Something is
missing
Control / Complexity for Client
Less Ruby
Monday, June 10, 13
Transponder JS
http://www.github.com/zacksiri/transponder
Extracted from Codemy
Monday, June 10, 13
3 Core Components
• Helpers
• Presenters
• Services
Monday, June 10, 13
CH.calendar = Codemy.Helpers.Calendar =
  dateOnly: (date_time) ->
    moment(date_time).format('YYYY-MM-DD')
 
  timeInISO: (date_time) ->
    moment(date_time).format('YYYY-MM-DD HH:mm:ss Z')
 
  timeInHour: (date_time) ->
    moment(date_time).format('HH:mm A')
Monday, June 10, 13
class CommentsPresenter extends Transponder.Presenter
  presenterName: 'comments'
  modelName: 'comment'
 
  index: ->
    if @params.page
      CH.infiniteLoader.loadNext
        element: @element
        response: @response
        modelName: @modelName
        putAt: 'prepend'
 
  show: ->
    $(@element).replaceWith(@response)
    $(@element).trigger('codemy:services:highlight')
 
....
 
  create: ->
    $('#new_comment').replaceWith(@response)
    $(".comment:last").effect('highlight', {}, 500)
 
  destroy: ->
    $(@element).fadeOut 300, ->
      $(this).remove()
Monday, June 10, 13
• maps to your controller actions
• calls helper functions when needed
• trigger services
• modify the DOM as needed
Presenters
Monday, June 10, 13
How does it work?
Monday, June 10, 13
class CommentsPresenter extends Transponder.Presenter
  presenterName: 'comments'
  modelName: 'comment'
 
  index: ->
    # your code for modifying the DOM
    # listens for event ujs:comments:index
 
  update: ->
    # listens for even ujs:comments:update
...
• ujs:comments:index triggers index()
• ujs:comments:show triggers show()
• ujs:comments:edit triggers edit()
• ujs:comments:update triggers update()
• ujs:comments:create triggers create()
• ujs:comments:destroy triggers destroy()
Monday, June 10, 13
Ok so how do I trigger the
event?
Monday, June 10, 13
$('#comments').trigger("<%= j ujs_event_type %>", "<%= j
render 'comments' %>");
app/views/comments/index.js.erb
app/views/comments/update.js.erb
$('#comment_1').trigger("<%= j ujs_event_type %>", "<%= j
render @comment %>");
{
ujs:comments:update
{
controller_name:action_name
Monday, June 10, 13
class CommentsPresenter extends Transponder.Presenter
  presenterName: 'comments'
  modelName: 'comment'
 
  index: ->
    if @params.page
      CH.infiniteLoader.loadNext
        element: @element
        response: @response
        modelName: @modelName
        putAt: 'prepend'
 
  update: ->
    $(@element).replaceWith(@response)
 
  ...
Monday, June 10, 13
Presenters Provide
• Better code reusability (Dryer)
• Cleaner
• Provides Structure
• Use what you already know!
• Logicless View in Rails
Monday, June 10, 13
What are services?
Monday, June 10, 13
Monday, June 10, 13
<select>
  <option value="drafting">drafting</option>
  <option value="request_approval">
awaiting approval
</option>
</select>
Monday, June 10, 13
class Codemy.Services.SubmitOnChange extends
Transponder.Service
  serviceName: 'codemy:services:submit_on_change'
 
  serve: ->
    @element.on 'change', (e) ->
      e.preventDefault()
      form = $(this).parents('form')
      $.ajax
        url: form.attr('action')
        type: 'PUT'
        dataType: 'script'
        data: $(form).serialize()
Monday, June 10, 13
<select class="submit_on_change">
  <option value="drafting">drafting</option>
  <option value="request_approval">
awaiting approval
</option>
</select>
$('body.courses.index').trigger('codemy:services:submit_on_change');
<select class="submit_on_change submit_on_change_active">
  <option value="drafting">drafting</option>
  <option value="request_approval">
awaiting approval
</option>
</select>
Monday, June 10, 13
Transponder.service_manifest = ->
  $("body.questions,
     body.apprentice.objectives.show,
     body.mentor.owned_levels.show,
     body.mentor.objectives.show,
     body.mentor.posts,
     body.posts.show").trigger       'codemy:services:live_preview'
 
  $("body.questions,
     body.mentor.posts").trigger     'codemy:services:tag_select'
 
  $("body.questions,
     body.apprentice,
     body.mentor,
     body.activities,
     body.posts.show").trigger       'codemy:services:highlight'
Monday, June 10, 13
What Services Do
• Write once use everywhere (again Dryer code)
• Better Maintainability
• Makes sure it doesn’t run on a node that has that service
already running
• Makes it easier to manage all your code via manifest
Monday, June 10, 13
How do they all Work
Together?
Monday, June 10, 13
class BadgesPresenter extends Transponder.Presenter
  nameSpace: "mentor"
  presenterName: "badges"
  modelName: "badge"
 
  show: ->
    $(@element).replaceWith(@response)
    $(@element).trigger('codemy:services:poller')
    $(@element).trigger('codemy:services:uploader')
 
  update: ->
    @show()
Monday, June 10, 13
Monday, June 10, 13
$(document).ready
triggers uploader service
User
uploads uploader service runs
Runs Update action in
Presenter
Triggers poller
service
renders processed image to
browser
through presenter
1
2
3
4
5
6
Monday, June 10, 13
Transponder works with
Everything
Monday, June 10, 13
Not Saying don’t use
Backbone
Monday, June 10, 13
Use the right tools for
the job.
Monday, June 10, 13
Codemy uses Turbolinks with
Transponder and Backbone when
appropriate
Monday, June 10, 13
Transponder is out!
http://www.github.com/zacksiri/transponder
Monday, June 10, 13
# TODO:
• Clean up some APIs
• Add Documentation
• Video Screencasts
• More Generators
• Example Rails Project
Monday, June 10, 13
Thank You!
@codemy_net
Questions?
@zacksiri
Monday, June 10, 13

More Related Content

PDF
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
PDF
Let jQuery Rock Your World
KEY
Developing api with rails metal
PDF
Git workflow in agile development
PDF
Tek 2013 - Building Web Apps from a New Angle with AngularJS
PDF
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
PDF
Functional Reactive Programming in the Netflix API
PDF
Dependency Injection @ AngularJS
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
Let jQuery Rock Your World
Developing api with rails metal
Git workflow in agile development
Tek 2013 - Building Web Apps from a New Angle with AngularJS
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
Functional Reactive Programming in the Netflix API
Dependency Injection @ AngularJS

Similar to A Better UJS for Rails (20)

PDF
Bytecode manipulation with Javassist and ASM
PDF
Deprecating ActiveRecord Attributes without making Zombies
PDF
Nomethoderror talk
PDF
Angular JS Routing
KEY
#NewMeetup Performance
PDF
Zero-config JavaScript apps with RaveJS -- SVCC fall 2014
PDF
Delivering a Responsive UI
PDF
Lone StarPHP 2013 - Building Web Apps from a New Angle
PDF
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
PDF
Gon gem. For RDRC 2013, June 7
PDF
JavaScript Dependencies, Modules & Browserify
ODP
PrettyFaces URLRewrite for Servlet & JavaEE @ Devoxx 2010
PDF
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
PDF
Puppeteer - A web scraping & UI Testing Tool
KEY
jQuery Anti-Patterns for Performance & Compression
PPT
AngularJS and SPA
KEY
jQuery Anti-Patterns for Performance
PPTX
Introduction à AngularJS
PDF
Backbone
PDF
Using Angular with Rails
Bytecode manipulation with Javassist and ASM
Deprecating ActiveRecord Attributes without making Zombies
Nomethoderror talk
Angular JS Routing
#NewMeetup Performance
Zero-config JavaScript apps with RaveJS -- SVCC fall 2014
Delivering a Responsive UI
Lone StarPHP 2013 - Building Web Apps from a New Angle
EWD 3 Training Course Part 36: Accessing REST and Web Services from a QEWD ap...
Gon gem. For RDRC 2013, June 7
JavaScript Dependencies, Modules & Browserify
PrettyFaces URLRewrite for Servlet & JavaEE @ Devoxx 2010
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
Puppeteer - A web scraping & UI Testing Tool
jQuery Anti-Patterns for Performance & Compression
AngularJS and SPA
jQuery Anti-Patterns for Performance
Introduction à AngularJS
Backbone
Using Angular with Rails
Ad

Recently uploaded (20)

PDF
August Patch Tuesday
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPT
Teaching material agriculture food technology
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
OMC Textile Division Presentation 2021.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
TLE Review Electricity (Electricity).pptx
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
Getting Started with Data Integration: FME Form 101
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
A Presentation on Artificial Intelligence
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
August Patch Tuesday
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Teaching material agriculture food technology
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
NewMind AI Weekly Chronicles - August'25-Week II
A comparative analysis of optical character recognition models for extracting...
OMC Textile Division Presentation 2021.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Digital-Transformation-Roadmap-for-Companies.pptx
Per capita expenditure prediction using model stacking based on satellite ima...
TLE Review Electricity (Electricity).pptx
Univ-Connecticut-ChatGPT-Presentaion.pdf
Getting Started with Data Integration: FME Form 101
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Programs and apps: productivity, graphics, security and other tools
Diabetes mellitus diagnosis method based random forest with bat algorithm
Mobile App Security Testing_ A Comprehensive Guide.pdf
A Presentation on Artificial Intelligence
Group 1 Presentation -Planning and Decision Making .pptx
Building Integrated photovoltaic BIPV_UPV.pdf
Ad

A Better UJS for Rails

  • 1. A Better UJS for Rails Codemy.net presents @zacksiriby: Monday, June 10, 13
  • 2. Javascript is a big part of Rails Project Monday, June 10, 13
  • 3. No real convention for working with JS files Monday, June 10, 13
  • 4. Backbone is Great but... Monday, June 10, 13
  • 5. I miss working with Ruby Monday, June 10, 13
  • 6. And then I saw Turbolinks... Monday, June 10, 13
  • 8. Turbolinks Backbone / MV* Control / Complexity for Client Less Ruby Monday, June 10, 13
  • 9. So I thought long and hard Monday, June 10, 13
  • 10. Turbolinks Backbone / MV* ? Something is missing Control / Complexity for Client Less Ruby Monday, June 10, 13
  • 12. 3 Core Components • Helpers • Presenters • Services Monday, June 10, 13
  • 13. CH.calendar = Codemy.Helpers.Calendar =   dateOnly: (date_time) ->     moment(date_time).format('YYYY-MM-DD')     timeInISO: (date_time) ->     moment(date_time).format('YYYY-MM-DD HH:mm:ss Z')     timeInHour: (date_time) ->     moment(date_time).format('HH:mm A') Monday, June 10, 13
  • 14. class CommentsPresenter extends Transponder.Presenter   presenterName: 'comments'   modelName: 'comment'     index: ->     if @params.page       CH.infiniteLoader.loadNext         element: @element         response: @response         modelName: @modelName         putAt: 'prepend'     show: ->     $(@element).replaceWith(@response)     $(@element).trigger('codemy:services:highlight')   ....     create: ->     $('#new_comment').replaceWith(@response)     $(".comment:last").effect('highlight', {}, 500)     destroy: ->     $(@element).fadeOut 300, ->       $(this).remove() Monday, June 10, 13
  • 15. • maps to your controller actions • calls helper functions when needed • trigger services • modify the DOM as needed Presenters Monday, June 10, 13
  • 16. How does it work? Monday, June 10, 13
  • 17. class CommentsPresenter extends Transponder.Presenter   presenterName: 'comments'   modelName: 'comment'     index: ->     # your code for modifying the DOM     # listens for event ujs:comments:index     update: ->     # listens for even ujs:comments:update ... • ujs:comments:index triggers index() • ujs:comments:show triggers show() • ujs:comments:edit triggers edit() • ujs:comments:update triggers update() • ujs:comments:create triggers create() • ujs:comments:destroy triggers destroy() Monday, June 10, 13
  • 18. Ok so how do I trigger the event? Monday, June 10, 13
  • 19. $('#comments').trigger("<%= j ujs_event_type %>", "<%= j render 'comments' %>"); app/views/comments/index.js.erb app/views/comments/update.js.erb $('#comment_1').trigger("<%= j ujs_event_type %>", "<%= j render @comment %>"); { ujs:comments:update { controller_name:action_name Monday, June 10, 13
  • 20. class CommentsPresenter extends Transponder.Presenter   presenterName: 'comments'   modelName: 'comment'     index: ->     if @params.page       CH.infiniteLoader.loadNext         element: @element         response: @response         modelName: @modelName         putAt: 'prepend'     update: ->     $(@element).replaceWith(@response)     ... Monday, June 10, 13
  • 21. Presenters Provide • Better code reusability (Dryer) • Cleaner • Provides Structure • Use what you already know! • Logicless View in Rails Monday, June 10, 13
  • 24. <select>   <option value="drafting">drafting</option>   <option value="request_approval"> awaiting approval </option> </select> Monday, June 10, 13
  • 25. class Codemy.Services.SubmitOnChange extends Transponder.Service   serviceName: 'codemy:services:submit_on_change'     serve: ->     @element.on 'change', (e) ->       e.preventDefault()       form = $(this).parents('form')       $.ajax         url: form.attr('action')         type: 'PUT'         dataType: 'script'         data: $(form).serialize() Monday, June 10, 13
  • 26. <select class="submit_on_change">   <option value="drafting">drafting</option>   <option value="request_approval"> awaiting approval </option> </select> $('body.courses.index').trigger('codemy:services:submit_on_change'); <select class="submit_on_change submit_on_change_active">   <option value="drafting">drafting</option>   <option value="request_approval"> awaiting approval </option> </select> Monday, June 10, 13
  • 27. Transponder.service_manifest = ->   $("body.questions,      body.apprentice.objectives.show,      body.mentor.owned_levels.show,      body.mentor.objectives.show,      body.mentor.posts,      body.posts.show").trigger       'codemy:services:live_preview'     $("body.questions,      body.mentor.posts").trigger     'codemy:services:tag_select'     $("body.questions,      body.apprentice,      body.mentor,      body.activities,      body.posts.show").trigger       'codemy:services:highlight' Monday, June 10, 13
  • 28. What Services Do • Write once use everywhere (again Dryer code) • Better Maintainability • Makes sure it doesn’t run on a node that has that service already running • Makes it easier to manage all your code via manifest Monday, June 10, 13
  • 29. How do they all Work Together? Monday, June 10, 13
  • 30. class BadgesPresenter extends Transponder.Presenter   nameSpace: "mentor"   presenterName: "badges"   modelName: "badge"     show: ->     $(@element).replaceWith(@response)     $(@element).trigger('codemy:services:poller')     $(@element).trigger('codemy:services:uploader')     update: ->     @show() Monday, June 10, 13
  • 32. $(document).ready triggers uploader service User uploads uploader service runs Runs Update action in Presenter Triggers poller service renders processed image to browser through presenter 1 2 3 4 5 6 Monday, June 10, 13
  • 34. Not Saying don’t use Backbone Monday, June 10, 13
  • 35. Use the right tools for the job. Monday, June 10, 13
  • 36. Codemy uses Turbolinks with Transponder and Backbone when appropriate Monday, June 10, 13
  • 38. # TODO: • Clean up some APIs • Add Documentation • Video Screencasts • More Generators • Example Rails Project Monday, June 10, 13