Disparando JavaScript por página no Rails
Leia em 2 minutos
Executar JavaScript por escopo de página é algo que todo mundo precisa. Existem diversas soluções disponíveis, mas faz algum tempo que uso uma biblioteca que criei chamada Dispatcher. Com ela é possível especificar callbacks before
e after
, além de ter executar automaticamente o JavaScript de uma página.
Neste artigo vou mostrar como você pode usar esta biblioteca, integrando-a inclusive com o Turbolinks.
Instalação
Para instalar o Dispatcher, você pode copiar os arquivos da biblioteca para o diretório da sua aplicação. Claro que isso é pedir para que os arquivos fiquem desatualizados, então vou mostrar como usar o Bower.
Crie o arquivo .bowerrc
e configure o diretório de instalações para vendor/assets/components
.
{
"directory": "vendor/assets/components"
}
Agora, crie o arquivo bower.json
, que irá armazenar suas dependências.
{
"name": "myapp",
"version": "0.0.1",
"private": true
}
Finalmente, instale a biblioteca.
$ bower install dispatcher --save
bower dispatcher#* not-cached git://github.com/fnando/dispatcher-js.git#*
bower dispatcher#* resolve git://github.com/fnando/dispatcher-js.git#*
bower dispatcher#* download https://github.com/fnando/dispatcher-js/archive/v0.1.0.tar.gz
bower dispatcher#* extract archive.tar.gz
bower dispatcher#* resolved git://github.com/fnando/dispatcher-js.git#0.1.0
bower dispatcher#~0.1.0 install dispatcher#0.1.0
dispatcher#0.1.0 vendor/assets/components/dispatcher
Se você quer saber mais sobre o Bower, veja este artigo que escrevi sobre o assunto.
No arquivo app/assets/javascript/application.js
, adicione as linhas abaixo:
//= require jquery
//= require dispatcher
Pronto! Agora você já pode escrever o código do seu roteador.
Definindo suas rotas
A ideia do Dispatcher se baseia em ter um controller e action. A definição da rota pode ser feita em um objeto, como no exemplo abaixo.
var MyApp = {};
MyApp.site = {
index: function(){
console.log("Welcome to the home page");
}
};
Para executar esta rota, você deve executar a função Dispatcher.run()
, como no exemplo abaixo:
Dispatcher.run(MyApp, "site#index");
Agora que você já sabe como é o conceito por trás da execução, vamos automatizar o processo em uma aplicação Rails.
Para definir a rota que deve ser executada no JavaScript, vamos criar um helper chamado dispatcher_route
. Ele irá compor a rota no formato controller#action
.
module ApplicationHelper
def dispatcher_route
controller_name = controller_path.gsub(/\//, "_")
"#{controller_name}##{action_name}"
end
end
Adicione um atributo data-route
no elemento <body>
com o valor retornado pelo este método.
<body data-route="<%= dispatcher_route %>"></body>
Crie um arquivo app/assets/javascripts/boot.js
que irá executar a função Dispatcher.run
quando a página estiver pronta para ser manipulada. Você precisará informar o aplicativo e a rota.
$(function(){
Dispatcher.run(MyApp, $("body").data("route"));
});
No entanto, você não precisa fazer esta configuração manualmente; Se você quiser usar a sugestão acima através do atributo data-route
, execute apenas a função Dispatcher.init
. Note que você não precisa envelopar a chamada no wrapper do jQuery, já que isso é feito internamente.
Dispatcher.init(MyApp);
Pronto! O Dispatcher irá executar o JavaScript específico para aquela página, caso ele tenha sido definido.
Executando coisas antes e depois das ações
O Dispatcher permite executar coisas antes e depois de uma ação. Você pode definir callbacks globais ou específicos de um controller.
Para definir um callback global, crie os atributos before
e after
na raíz do objeto que representa o aplicativo.
var MyApp = {
before: function() {
console.log("[before] Executed in every single page!");
}
, after: function() {
console.log("[after] Executed in every single page!");
}
};
Você também pode definir esses mesmos callbacks por controller.
var MyApp = {};
MyApp.site = {
before: function() {
console.log("[before] Executed before each site's actions!");
}
, after: function() {
console.log("[after] Executed after each site's actions!");
}
};
Integrando com o Turbolinks
Se você usa Turbolinks, saiba que o Dispatcher possui suporte para ele. A configuração é a mesma que a versão sem o Turbolinks; basta executar a função Dispatcher.init
, passando o aplicativo. A rota é retirada do atributo data-route
do elemento <body>
.
var MyApp = {};
Dispatcher.init(MyApp); // Turbolinks
O Turbolinks dispara o evento page:load
sempre que uma página for carregada. O Dispatcher ouve este evento e também o load
; por isso não é preciso fazer nada especial para que o Dispatcher funcione com ou sem Turbolinks.
Finalizando
Como você pode perceber, executar JavaScript específico de uma página pode ser bastante simples, sem ter que recorrer ao truque do content_for
.
Lembre-se que a ideia é usar o Dispatcher como um roteador. Por isso, escreva o seu código de forma modular e apenas inicialize os objetos necessários para que a mágica aconteça!