Avoiding Safari exit confirmation dialog for dirty forms

Safari asks close confirmation if a form field isn't clean

Safari asks for your confirmation if you accidentally try to close a page if you filled a form but never submitted. This saved my day more than once and it’s undoubtedly helpful.

The problem is that if you’re sending the form via ajax Safari still thinks you’re loosing some data. Luckily the fix is easy:

var postBody = document.querySelector('textarea.post-body')
postBody.defaultValue = postBody.value

You should always specify the :inverse_of option on AR associations

Directly from ActiveRecord documentation on bi-directional associations:

Bi-directional associations

When you specify an association there is usually an association on the associated model that specifies the same relationship in reverse. For example, with the following models:

class Dungeon < ActiveRecord::Base
  has_many :traps
  has_one :evil_wizard
end

class Trap < ActiveRecord::Base
  belongs_to :dungeon
end

class EvilWizard < ActiveRecord::Base
  belongs_to :dungeon
end

The traps association on Dungeon and the dungeon association on Trap are the inverse of each other and the inverse of the dungeon association on EvilWizard is the evil_wizard association on Dungeon (and vice-versa). By default, Active Record doesn’t know anything about these inverse relationships and so no object loading optimization is possible. For example:

d = Dungeon.first
t = d.traps.first
d.level == t.dungeon.level # => true
d.level = 10
d.level == t.dungeon.level # => false

The Dungeon instances d and t.dungeon in the above example refer to the same object data from the database, but are actually different in-memory copies of that data. **Specifying the :inverse_of option on associations lets you tell Active Record about inverse relationships and it will optimise object loading. For example, if we changed our model definitions to:

class Dungeon < ActiveRecord::Base
  has_many :traps, inverse_of: :dungeon
  has_one :evil_wizard, inverse_of: :dungeon
end

class Trap < ActiveRecord::Base
  belongs_to :dungeon, inverse_of: :traps
end

class EvilWizard < ActiveRecord::Base
  belongs_to :dungeon, inverse_of: :evil_wizard
end

Then, from our code snippet above, d and t.dungeon are actually the same in-memory instance and our final d.level == t.dungeon.level will return true.

There are limitations to :inverse_of support:

  • does not work with :through associations.
  • does not work with :polymorphic associations.
  • for belongs_to associations has_many inverse associations are ignored.

“Use Node.js FOR SPEED” — @RoflscaleTips

I obeyed, therefore I wrote an opal NPM package.

Now I can trash Rails and opal-rails and start working on Node only!

server = Server.new 3000
server.start do
  [200, {'Content-Type' => 'text/plain'}, ["Hello World!n"]]
end

For it I had to write the Server class:

class Server
  def initialize port
    @http = `require('http')`
    @port = port
  end

  def start &block
    %x{
      this.http.createServer(function(req, res) {
        var rackResponse = (block.call(block._s, req, res));
        res.end(rackResponse[2].join(' '));
      }).listen(this.port);
    }
  end
end

Put them in app.opal and then start the server:

$ npm install -g opal      # <<< install the NPM package first!
$ opal-node app

The running app

YAY! now I can roflSCALE all of my RAils apps!!1

Cross posted from Eliæ

Stop writing JavaScript and get back to Ruby!

Cross posted from: Eliæ

Remeber that feeling that you had after having tried CoffeeScript getting back to a project with plain JavaScript and felt so constricted?

Well, after re-writing a couple of coffee classes with OpalRuby I felt exactly that way, and with 14.9KB of footprint (min+gz, jQuery is 32KB) is a complete no brainer.

So let’s gobble up our first chunk of code, that will salute from the browser console:

puts 'hi buddies!'

You wonder how that gets translated?

Fear that it will look like this?

'egin',cb='bootstrap',u='clear.cache.gif',z='content',bc='end',lb='gecko',mb='g
cko1_8',yb='gwt.hybrid',xb='gwt/standard/standard.css',E='gwt:onLoadErrorFn',B=
'gwt:onPropertyErrorFn',y='gwt:property',Db='head',qb='hosted.html?hello',Cb='h
ref',kb='ie6',ab='iframe',t='img',bb="javascript:''",zb='link',pb='loadExternal
Refs',v='meta',eb='moduleRequested',ac='moduleStartup',jb='msie',w='name',gb='o
pera',db='position:absolute;width:0;height:0;border:none',Ab='rel',ib='safari',
rb='selectingPermutation',x='startup',m='hello',Bb='stylesheet',ob='unknown',fb
='user.agent',hb='webkit';var fc=window,k=document,ec=fc.__gwtStatsEvent?functi
on(a){return fc.__gwtStatsEvent(a)}:null,zc,pc,kc,jc=l,sc={},Cc=[],yc=[],ic=[],
vc,xc;ec&&ec({moduleName:m,subSystem:x,evtGroup:cb,millis:(new Date()).getTime(
),type:nb});if(!fc.__gwt_stylesLoaded){fc.__gwt_stylesLoaded={}}if(!fc.__gwt_sc
riptsLoaded){fc.__gwt_scriptsLoaded={}}function oc(){var b=false;try{b=fc.exter

Nope! it’s Chuck Testa

(function() {
  return this.$puts("hi buddies!")
}).call(Opal.top);

But it will be obviously a mess to integrate it with existing javascript!!1

Let’s how to add #next and #prev to the Element class:

class Element
  def next(selector = '')
    element = nil
    `element = jQuery(this.el).next(selector)[0] || nil;`
    Element.new element if element
  end
end

But I’m on Rails!

Here you served:

gem 'opal-rails'

Which il provide you a requirable libraries for application.js

//= require opal
//= require rquery

and the .opal extension for your files

# app/assets/javascripts/hi-world.js.opal

puts "G'day world!"

A template handler:

# app/views/posts/show.js.opal.erb

Element.id('<%= dom_id @post %>').show

and a Haml filter!

-# app/views/posts/show.html.haml

%article= post.body

%a#show-comments Display Comments!

.comments(style="display:none;")
  - post.comments.each do |comment|
    .comment= comment.body

:opal
  Document.ready? do
    Element.id('show-comments').on :click do
      Element.find('.comments').first.show
      false # aka preventDefault
    end
  end

Diego Franciosi is a Mikamayer (since 2010)

Diego Franciosi was a web addicted, previous work interests include OpenSource software, web 2.0 applications with PHP frameworks (symfony), dynamic technologies (AJAX) and javascript libraries (YUI, jQuery), CSS design, Java, social networking, Linux and Mac OS X O.S.

The Face

…but now he’s all about Ruby on Rails, coffescript, vim, agile practices, paleo diet, the pomodoro technique, technical books, continuous improvement …and fashion!

You can follow him on GitHub and Twitter.