<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vinicius Ebersol &#187; AJAX</title>
	<atom:link href="http://vebersol.net/category/ajax/feed/" rel="self" type="application/rss+xml" />
	<link>http://vebersol.net</link>
	<description>Blog on Rails</description>
	<lastBuildDate>Mon, 07 May 2012 03:07:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Ajax crossdomain crossbrowser</title>
		<link>http://vebersol.net/2012/04/13/ajax-crossdomain-crossbrowser/</link>
		<comments>http://vebersol.net/2012/04/13/ajax-crossdomain-crossbrowser/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 14:06:20 +0000</pubDate>
		<dc:creator>Vinicius Ebersol</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://vebersol.net/?p=208</guid>
		<description><![CDATA[O título do link pode parecer feio, mas é isso mesmo. É possível fazer esse tipo de requisição assíncrona usando a função $.ajax do jQuery e o dataType JSONP. Abaixo um exmplo do que eu fiz para testar. Ajax crossdomain &#8230; <a href="http://vebersol.net/2012/04/13/ajax-crossdomain-crossbrowser/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>O título do link pode parecer feio, mas é isso mesmo. É possível fazer esse tipo de requisição assíncrona usando a função <a title="$.ajax" href="http://api.jquery.com/jQuery.ajax/">$.ajax</a> do <a title="jQuery home" href="http://jquery.com">jQuery</a> e o dataType <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>.</p>
<p>Abaixo um exmplo do que eu fiz para testar. Ajax crossdomain testado inclusive no IE6.</p>
<p>Uma ressalva é importante: Eu usei o <a href="http://developer.yahoo.com/yql/">YQL</a> que é uma API do <a href="http://www.yahoo.com/">Yahoo</a> que retorna um jSON de uma URL qualquer.</p>
<pre>&lt;!doctype HTML&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Test&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"&gt;&lt;/script&gt;
        &lt;script type="text/javascript"&gt;
            // a variavel deve ser global para permitir a execução do callback em um javascript orientado a objetos.
            var externalAjax;

            var ExternalAjax = function() {
                this.url = 'http://vebersol.net';
                this.format = 'html'; //html, json
                this.jsonURL = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22'+encodeURIComponent(this.url)+'%22&amp;format='+this.format+'&amp;diagnostics=true&amp;callback=externalAjax.getJsonCallback';

                this.init();
            }

            ExternalAjax.prototype = {
                init: function() {
                    $.ajax({
                      url: this.jsonURL,
                      dataType: 'jsonp'
                    });
                },
                // o nome desta função é passada como parâmetro, chamado callback na variável jsonURL. Ela vai ser executada assim que a request for finalizada.    
                getJsonCallback: function(data) {
                    if (this.format == 'html') {
                        $('body').append(data.results[0]);
                    }
                    else if (this.format == 'json') {
                        // execute o seu código para usar o seu jSON como bem entender...
                        console.log(data);
                    }
                }
            }

            $(function() {
                externalAjax = new ExternalAjax();
            });
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://vebersol.net/2012/04/13/ajax-crossdomain-crossbrowser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Abra sua caixa de ferramentas com Dojo</title>
		<link>http://vebersol.net/2009/09/10/abra-sua-caixa-de-ferramentas-com-dojo/</link>
		<comments>http://vebersol.net/2009/09/10/abra-sua-caixa-de-ferramentas-com-dojo/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 16:46:28 +0000</pubDate>
		<dc:creator>Vinicius Ebersol</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://vebersol.net/?p=108</guid>
		<description><![CDATA[Antes de tudo, Dojo não é só mais um framework Javascript como jQuery, Prototype e Mootols. Em muitos casos esses facilitam o desenvolvimento, no entanto, quando a questão é desempenho, somente agilidade no processo de desenvolvimento não é uma boa &#8230; <a href="http://vebersol.net/2009/09/10/abra-sua-caixa-de-ferramentas-com-dojo/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-110 alignleft" style="border: 0pt none; margin: 10px;" title="dojo" src="http://vebersol.net/wp-content/uploads/2009/09/dojo.png" alt="dojo toolkit logo" width="223" height="163" /></p>
<p>Antes de tudo, <a href="http://www.dojotoolkit.org/" target="_self">Dojo</a> não é só mais um framework Javascript como <a href="http://jquery.com">jQuery</a>, <a href="http://www.prototypejs.org/">Prototype</a> e <a href="http://mootools.net/">Mootols</a>. Em muitos casos esses facilitam o desenvolvimento, no entanto, quando a questão é desempenho, somente agilidade no processo de desenvolvimento não é uma boa escolha.</p>
<p>Desenvolver aplicações web de grande porte significa preocupar-se com desempenho não só do lado do servidor, o cliente (alvo principal) deve ser peça fundamental. Incluir dezenas de arquivos javascript com funções que muitas vezes sequer serão usadas, causa um aumento de tráfego pouco significante se analisarmos as coisas de forma isolada, mas imagine um excesso de 10kb a cada request feita por milhões de usuários, isso pode gerar um excesso de gigabytes por mês dependendo do número de acessos mensais, causando uma lentidão nas respostas do servidor.</p>
<h3>Acerca do desempenho no lado do cliente</h3>
<p>Um teste realizado <a href="http://blog.creonfx.com/javascript/mootools-vs-jquery-vs-prototype-vs-yui-vs-dojo-comparison-revised">neste blog</a> mostrou resultados surpreendentes relacionando frameworks e browsers. Na média, o Dojo é o mais rápido de todos os frameworks.</p>
<p style="text-align: center;"><img class="size-full wp-image-118 aligncenter" title="speed-compersion-graph" src="http://vebersol.net/wp-content/uploads/2009/09/speed-compersion-graph.jpg" alt="speed-compersion-graph" width="550" height="508" /></p>
<h3>Sobre o tráfego</h3>
<p>Muitos desenvolvedores usam jQuery e Prototype, inclusive eu. O jQuery tem todo o seu core em um único arquivo, já o prototype tem arquivos separados que você inclui dependendo de suas necessidades. Para esse segundo caso, creio que você não fará um header diferente para cada página que criar, portanto, na maioria das vezes inluímos todos os arquivos que irão usar em toda aplicação.</p>
<p>A facilidade do Dojo nesse aspecto está no seu maior segredinho: ele é dividido em dezenas de partes que você inclui somente de acordo com a sua necessidade utilizando um médoto próprio do dojo.</p>
<pre id="line31">dojo.require("dojo.NodeList-fx");</pre>
<p>A primeira vista pode parecer semelhante ao prototype, porém, se você analizar o código que está contido em cada arquivo vai entender. São em média 50 a 100 linhas incluíndo comentários e quebras de linha por arquivo (na versão não reduzida do dojo). Comparando com o arquivo <em>effects.js</em> do Prototype (que contém aproximadamente 1200 linhas) é algo realmente significativo.</p>
<h3>Dijit: O diferencial do Dojo</h3>
<p>O melhor do Dojo com certeza é a sua biblioteca de widgets, chamada <a href="http://dojotoolkit.org/projects/dijit">Dijit</a>. Com ela você pode adicionar elementos à sua aplicação tornando a experiência do usuário muito satisfatória. Existem soluções semelhantes para jQuery e Prototype, porém, você terá que ir em busca das soluções que necessita e contar com a sorte para que o desenvolvedor do plugin tenha desenvolvido algo que irá funcionar corretamente e suprir as suas necessidades.</p>
<p>O mais importante de tudo é que o Dijit é internacionalizado e em muitos casos, acessível. Veja aqui algumas <a href="http://dojocampus.org/explorer/#Dijit">features do Dijit</a>.</p>
<h3>DojoX</h3>
<p>O <a href="http://dojocampus.org/explorer/#Dojox">DojoX</a> é uma área de desenvolvimento de extensões, uma espécie de incubadora de novas idéias que mais tarde podem estar disponíveis na ferramenta principal ou serem removidas se não obtiverem o sucesso esperado. Podem não ser internacionalizadas e não ter a mesma qualidade dos widgets do Dijit, porém, são sempre coisas novas que podem ser úteis na hora do aperto.</p>
<h3>Conclusão</h3>
<p>Utilizar Dojo é uma revisão de conceitos, mas como todo bom desenvolvedor dedicar um pouco de tempo ao aprendendizado da &#8220;filosofia&#8221; do Dojo pode torná-lo um desenvolvedor versátil e independente de tecnologias, pois pode ocorrer de uma oportunidade de emprego solicitar experiências com esta e(ou) aquela ferramenta de acordo com a aplicação ou ainda as determinações do cliente.</p>
]]></content:encoded>
			<wfw:commentRss>http://vebersol.net/2009/09/10/abra-sua-caixa-de-ferramentas-com-dojo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Upload de arquivos com AJAX em Ruby on Rails</title>
		<link>http://vebersol.net/2008/02/13/upload-de-arquivos-com-ajax-em-ruby-on-rails/</link>
		<comments>http://vebersol.net/2008/02/13/upload-de-arquivos-com-ajax-em-ruby-on-rails/#comments</comments>
		<pubDate>Wed, 13 Feb 2008 07:27:42 +0000</pubDate>
		<dc:creator>Vinicius Ebersol</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Um dos maiores problemas para quem desenvolve sistemas utilizando AJAX é o upload de arquivos. Se você ouviu dizer que não era possível fazer upload de arquivos em AJAX, acredite, utilizando AJAX simplesmente não dá mesmo, porém existem maneiras de &#8230; <a href="http://vebersol.net/2008/02/13/upload-de-arquivos-com-ajax-em-ruby-on-rails/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Um dos maiores problemas para quem desenvolve sistemas utilizando AJAX é o upload de arquivos. Se você ouviu dizer que não era possível fazer <strong>upload de arquivos em AJAX</strong>, acredite, utilizando AJAX simplesmente não dá mesmo, porém existem maneiras de <strong>simular um upload assíncrono</strong>, como uma que eu achei no site do Khamsouk Souvanlasy, o <a href="http://khamsouk.souvanlasy.com/">code_fu</a>.  Este tutorial é uma <strong>adaptação</strong> do tutorial <a href="http://khamsouk.souvanlasy.com/2007/5/1/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent"><strong>AJAX file uploads in Rails using attachment_fu and responds_to_parent</strong></a> do blog do Khamsouk Souvanlasy.</p>
<p><strong>Passo 1:  Escolha um plugin de upload de arquivos</strong></p>
<p>Sim, é possível que você utilize seu próprio sistema de arquivos, mas sempre é bom utilizar plugins completos como os que citarei abaixo, pois lhe darão mais recursos. Os plugins recomendados são:</p>
<ol>
<li><a href="http://www.kanthak.net/opensource/file_column/">File_column</a></li>
<li><a href="http://svn.techno-weenie.net/projects/plugins/acts_as_attachment/">acts_as_attachment</a></li>
<li><a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a></li>
</ol>
<p>Neste caso, usarei attachment_fu, que é o plugin que eu utilizo para as minhas aplicações e que coincidentemente no tutorial é utilizado. Mas você pode utilizar qualquer um deles.</p>
<p><strong>Passo 2: Escolha o processador de imagens que irá utilizar</strong></p>
<p>Como neste caso, o upload de arquivos realizado é de imagens e este irá gerar uma thumb, é necessário utilizar um rocessador de imagens que reduzirá as imagens. É possível utilizar os seguintes processadores de imagens:</p>
<ol>
<li><a href="http://seattlerb.rubyforge.org/ImageScience.html">image_science</a></li>
<li><a href="http://rmagick.rubyforge.org/">RMagick</a></li>
<li><a href="http://rubyforge.org/projects/mini-magick/">minimagick</a></li>
</ol>
<p>Eu utilizo o <strong>RMagick</strong>, mas como foi um saco conseguir instalá-lo no <strong>Ubuntu</strong>, recomendo que sigam os passos do tutorial, que utiliza o <strong>minimagick</strong>.</p>
<p><strong>Passo 3: Instalando minimagick e o plugin attachment_fu</strong></p>
<p>Dependendo do seu sistema operacional, a instalação do processador de imagens pode ser longa e complicada, como para mim foi. No meu caso, há problemas nos pacotes oferecidos pelo repositório do ubuntu e do gem. Eu instalei o RMagick em uma versão anterior a ofericida no pacote do Ubuntu.  Atenção: No pacote de softwares do Ubuntu, o nome do processador está sem o k, ou seja, <strong>RMagic</strong>.</p>
<ul>
<li>RMagick/ImageMagick: <a href="http://rmagick.rubyforge.org/install-osx.html">Mac OS X</a>, <a href="http://rmagick.rubyforge.org/install-linux.html">Linux</a>, and <a href="http://rmagick.rubyforge.org/install-faq.html#win">Windows</a></li>
<li>FreeImage/image_science: <a href="http://seattlerb.rubyforge.org/ImageScience.html">Mac OS X, Linux</a></li>
<li>To install minimagick:</li>
</ul>
<blockquote><p>$ sudo gem install mini_magick</p></blockquote>
<p>Para instalar o plugin no attachment_fu:</p>
<blockquote><p> script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/</p></blockquote>
<p><strong>Passo 4: Adicione o upload ao seu código:</strong></p>
<p>No tutorial ele utiliza RESTful, e como eu também utilizo, recomendo que siga a dica e comece a implementar RESTful em suas aplicações. No tutorial ele recomenda <a href="http://ueckerman.net/2007/04/24/the-basics-of-rest-in-rails/">esta leitura</a>, mas eu vou recomendar também <a href="http://www.akitaonrails.com/2008/1/25/screencast-de-restful-rails-fcil">este screencast</a> do <strong><a href="http://www.akitaonrails.com/">Fábio Akita</a></strong>.</p>
<p>Para gerar um Scaffold RESTful, utilize o comando:</p>
<blockquote><p> ruby script/generate scaffold_resource asset filename:string content_type:string size:integer width:integer height:integer parent_id:integer thumbnail:string created_at:datetime</p></blockquote>
<p>Este comando irá criar um controller, um model, as views e a migration de um Scaffold RESTful. Além disso, é possível observar que ele já informa quais são os campos da migration, que no caso ficará assim:</p>
<pre>
<span class="keyword">class</span> <span class="type">CreateAssets</span> &lt; <span class="type">ActiveRecord</span>::<span class="type">Migration</span>
  <span class="keyword">def</span> <span class="function-name">self.up</span>
    create_table <span class="constant">:assets</span> <span class="keyword">do</span> |t|
      t.column <span class="constant">:filename</span>, <span class="constant">:string</span>
      t.column <span class="constant">:content_type</span>, <span class="constant">:string</span>
      t.column <span class="constant">:size</span>, <span class="constant">:integer</span>
      t.column <span class="constant">:width</span>, <span class="constant">:integer</span>
      t.column <span class="constant">:height</span>, <span class="constant">:integer</span>
      t.column <span class="constant">:parent_id</span>, <span class="constant">:integer</span>
      t.column <span class="constant">:thumbnail</span>, <span class="constant">:string</span>
      t.column <span class="constant">:created_at</span>, <span class="constant">:datetime</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span>

  <span class="keyword">def</span> <span class="function-name">self.down</span>
    drop_table <span class="constant">:assets</span>
  <span class="keyword">end</span>
<span class="keyword">end</span></pre>
<p>No modelo, você deve inserir estes dados para que seja possível enviar arquivos:</p>
<pre>
<span class="keyword">class</span> <span class="type">Asset</span> &lt; <span class="type">ActiveRecord</span>::<span class="type">Base</span>
  has_attachment  <span class="constant">:storage</span> =&gt; <span class="constant">:file_system</span>,
                  <span class="constant">:max_size</span> =&gt; 1.megabytes,
                  <span class="constant">:thumbnails</span> =&gt; { <span class="constant">:thumb</span> =&gt; <span class="string">'80x80&gt;'</span>, <span class="constant">:tiny</span> =&gt; <span class="string">'40x40&gt;'</span> },
                                    <span class="constant">:processor</span> =&gt; :<span class="type">MiniMagick</span> <span class="comment-delimiter"># </span><span class="comment">attachment_fu looks in this order: ImageScience, Rmagick, MiniMagick
</span>
  validates_as_attachment <span class="comment-delimiter"># </span><span class="comment">ok two lines if you want to do validation, and why wouldn't you?
</span><span class="keyword">end</span></pre>
<p>Sobre o funcionamento do attachment_fu, é algo complicado explicar em poucas linhas, dado o poder do plugin. Mas neste caso, a utilização é somente para o upload de imagem e a geração de uma miniatura dela. Para ter maiores informações sobre as outras opções do plugin, leia o arquivo README do plugin localizado em <em>vendor/plugins/attachment_fu/</em>.</p>
<p>Para que você entenda o funcionamento dos cadastros que o plugin faz no banco, e como utilizar ele, vou tentar explicar rapidamente:  O attachment_fu cadastra uma nova imagem no banco de dados que você escolher, fazendo uma query para cada imagem gerada, ou seja, no caso de você utilizar upload de imagem com uma miniatura, serão duas querys, uma com parent_id = nil e outra com o parent_id =  id da imagem em tamanho normal. Desta forma é possível identificar que a imagem com parent_id = nil é a imagem original e se você enviar outros dados como nome, email, eles estarão nesta query. Utilize <code>&lt;%= image_tag(image.public_filename(:thumb)) %&gt;</code> para exibir a miniatura de um cadastro.</p>
<p>Agora, faremos com que o form da view <code>new.rhtml</code>, consiga enviar arquivos, para isto, é preciso que o parâmetro do html chamado <strong>:multipart</strong> seja setado para <strong>true</strong>, como na view abaixo:</p>
<pre>
&lt;%= error_messages_for :asset %&gt;
&lt;% form_for(:asset, :url =&gt; assets_path, :html =&gt; { :multipart =&gt; true }) do |form| %&gt;
  &lt;<span class="function-name">p</span>&gt;
    &lt;<span class="function-name">label</span> <span class="variable-name">for</span>=<span class="string">"uploaded_data"</span>&gt;Upload a file:&lt;/<span class="function-name">label</span>&gt;
    &lt;%= form.file_field :uploaded_data %&gt;
  &lt;/<span class="function-name">p</span>&gt;
  &lt;<span class="function-name">p</span>&gt;
    &lt;%= submit_tag <span class="string">"Create"</span> %&gt;
  &lt;/<span class="function-name">p</span>&gt;
&lt;% end %&gt;</pre>
<p>Para o nosso exemplo, queremos ver a imagem (caso seja uma imagem) e o nome desta imagem.</p>
<pre>
&lt;<span class="function-name">h1</span>&gt;<span class="underline"><span class="bold">Listing assets</span></span>&lt;/<span class="function-name">h1</span>&gt;

&lt;<span class="function-name">ul</span> <span class="variable-name">id</span>=<span class="string">"assets"</span>&gt;
&lt;% @assets.each do |asset| %&gt;
&lt;<span class="function-name">li</span> <span class="variable-name">id</span>=<span class="string">"asset_&lt;%= asset.id %&gt;"</span>&gt;
&lt;% if asset.image? %&gt;
&lt;%= link_to(image_tag(asset.public_filename(:thumb))) %&gt;&lt;<span class="function-name">br</span> /&gt;
&lt;% end %&gt;
&lt;%= link_to(asset.filename, asset_path(asset)) %&gt; (&lt;%= link_to <span class="string">"Delete"</span>, asset_path(asset), :method =&gt; :delete, :confirm =&gt; <span class="string">"are you sure?"</span>%&gt;)
&lt;/<span class="function-name">li</span>&gt;
&lt;% end %&gt;
&lt;/<span class="function-name">ul</span>&gt;

&lt;<span class="function-name">br</span> /&gt;

&lt;%= link_to 'New asset', new_asset_path %&gt;</pre>
<p>Faça agora um rake <code>db:migrate</code> para criar a tabela necessária para o upload de arquivos no banco de dados. Com isto, você já pode iniciar o server (<code>script/server</code>) para utilizar o endereço <a href="http://localhost:3000/assets/new">http://localhost:3000/assets/new</a> para testar o seu scaffold em funcionamento juntamente com o plugin. Note que ele ainda não está funcionando em AJAX.</p>
<p>Quando você fizer o upload, você será direcionado para a index de assets, onde serão listados os dados presentes. Note que além da linha que contém o arquivo original, também será mostrada a linha referente a thumb. Podemos modificar o controller para exibir somente os arquivos com os arquivos originais, que na verdade é o que nos interessa, visto que somente nele existirão os dados extras que você usará além do arquivo, como nome e e-mail, por exemplo. Para visualizar a thumb, basta utilizar o seguinte método: <code>&lt;%= image_tag(image.public_filename(:thumb)) %&gt;</code></p>
<pre>
<span class="comment-delimiter">  # </span><span class="comment">GET /assets
</span>  <span class="comment-delimiter"># </span><span class="comment">GET /assets.xml
</span>  <span class="keyword">def</span> <span class="function-name">index</span>
    <span class="variable-name">@assets</span> = <span class="type">Asset</span>.find(<span class="constant">:all</span>, <span class="constant">:conditions</span> =&gt; {<span class="constant">:parent_id</span> =&gt; <span class="variable-name">nil</span>}, <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> rder</span> =&gt; <span class="string">'created_at DESC'</span>)
    respond_to <span class="keyword">do</span> |format|
      format.html <span class="comment-delimiter"># </span><span class="comment">index.rhtml
</span>      format.xml  { render <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ml</span> =&gt; <span class="variable-name">@assets</span>.to_xml }
    <span class="keyword">end</span>
  <span class="keyword">end</span></pre>
<p><strong>Passo 5: AJAX it!</strong>  Atualmente, o seus sistema funciona da seguinte forma:</p>
<ul>
<li>Você vai à página index</li>
<li>Clica no link <em>New Asset</em></li>
<li>Escolhe um arquivo e o envia pelo form</li>
<li>Você é direcionado à página index</li>
</ul>
<p>A partir de agora, nós faremos o upload de arquivo utilizando somente a página index, sem sair dela em nenhum momento do seu upload. Para isto, existem alguns passos básicos, como:</p>
<p>Insira as bibliotecas javascript do prototype/scriptaculous no seu layout:</p>
<pre>&lt;%= javascript_include_tag :defaults %&gt;</pre>
<p>Modifique a tag <code>form_for</code> para <code>remote_form_for</code> em seu formulário, que no caso é <code>new.rhtml</code></p>
<pre>&lt;%<span class="mmm-code-submode"> remote_form_for(:asset, :url =&gt; assets_path, :html =&gt; { :multipart =&gt; true }) do |f| </span>%&gt;</pre>
<p>Adicione <code>format.js</code> no sua action <code>create</code> no seu controller para permitir requisições AJAX.</p>
<pre>
  <span class="comment-delimiter"># </span><span class="comment">POST /assets
</span>  <span class="comment-delimiter"># </span><span class="comment">POST /assets.xml
</span>  <span class="keyword">def</span> <span class="function-name">create</span>
    <span class="variable-name">@asset</span> = <span class="type">Asset</span>.new(params[<span class="constant">:asset</span>])

    respond_to <span class="keyword">do</span> |format|
      <span class="keyword">if</span> <span class="variable-name">@asset</span>.save
        flash[<span class="constant">:notice</span>] = <span class="string">'Asset was successfully created.'</span>
        format.html { redirect_to asset_url(<span class="variable-name">@asset</span>) }
        format.xml  { head <span class="constant">:created</span>, <span class="constant">:location</span> =&gt; asset_url(<span class="variable-name">@asset</span>) }
        format.js
      <span class="keyword">else</span>
        format.html { render <span class="constant">:action</span> =&gt; <span class="string">"new"</span> }
        format.xml  { render <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ml</span> =&gt; <span class="variable-name">@asset</span>.errors.to_xml }
        format.js
      <span class="keyword">end</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span></pre>
<p>Crie um arquivo <code>create.rjs</code> na pasta <code>app/views/assets</code>, contendo isto:</p>
<pre>page.insert_html <span class="constant">:bottom</span>, <span class="string">"assets"</span>, <span class="constant">:partial</span> =&gt; <span class="string">'assets/list_item'</span>, <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> bject</span> =&gt; <span class="variable-name">@asset</span>
page.visual_effect <span class="constant">:highlight</span>, <span class="string">"asset_</span><span class="variable-name">#{@asset.id}</span><span class="string">"</span></pre>
<p>Crie uma partial chamada <code>_list_item.rhtml</code> na sua pasta <code>app/views/assets</code> para adicionar a listagem de dados o novo dado inserido.</p>
<pre>&lt;<span class="function-name">li</span> <span class="variable-name">id</span>=<span class="string">"asset_&lt;%= list_item.id %&gt;"</span>&gt;
&lt;% if list_item.image? %&gt;
&lt;%= link_to(image_tag(list_item.public_filename(:thumb))) %&gt;&lt;<span class="function-name">br</span> /&gt;
&lt;% end %&gt;
&lt;%= link_to(list_item.filename, asset_path(list_item))%&gt; (&lt;%= link_to_remote(<span class="string">"Delete"</span>, {:url =&gt; asset_path(list_item), :method =&gt; :delete, :confirm =&gt; <span class="string">"are you sure?"</span>}) %&gt;)
&lt;/<span class="function-name">li</span>&gt;</pre>
<p>Uma parte opcional é a exclusão AJAX, que você pode fazer criando o arquivo <code>destroy.rjs</code> na pasta <code>app/views/assets</code>.</p>
<pre>page.remove <span class="string">"asset_</span><span class="variable-name">#{@asset.id}</span><span class="string">"</span></pre>
<p>No controller, você deve adicionar o formato <code>format.js</code> na action <code>destroy</code>.</p>
<p>Para que o seu formulário seja utilizado tanto em uma área que é necessário o upload via AJAX, como em <code>index.rhtml</code>, quanto em uma área que o upload pode ser feito da forma convencional, como em <code>new.rhtml</code>, siga os seguintes passos:</p>
<p><code>_form.rhtml</code></p>
<pre>&lt;<span class="function-name">p</span>&gt;
  &lt;<span class="function-name">label</span> <span class="variable-name">for</span>=<span class="string">"uploaded_data"</span>&gt;Upload a file:&lt;/<span class="function-name">label</span>&gt;
  &lt;%=<span class="mmm-output-submode"> form.file_field :uploaded_data </span>%&gt;
&lt;/<span class="function-name">p</span>&gt;
&lt;<span class="function-name">p</span>&gt;
  &lt;%=<span class="mmm-output-submode"> submit_tag "Create" </span>%&gt;
&lt;/<span class="function-name">p</span>&gt;</pre>
<p><code>new.rhtml</code></p>
<pre>&lt;%<span class="mmm-code-submode"> form_for(:asset, :url =&gt; assets_path, :html =&gt; { :multipart =&gt; true }) do |form| </span>%&gt;
&lt;%=<span class="mmm-output-submode"> render(:partial =&gt; '/assets/form', <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> bject =&gt; form)</span>%&gt;
&lt;%<span class="mmm-code-submode"> end </span>%&gt;</pre>
<p>Adicione o formulário na sua action <code>index.rhtml</code>:</p>
<pre>&lt;%<span class="mmm-code-submode"> remote_form_for(:asset, :url =&gt; assets_path, :html =&gt; { :multipart =&gt; true }) do |form| </span>%&gt;
&lt;%=<span class="mmm-output-submode"> render(:partial =&gt; '/assets/form', <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> bject =&gt; form) </span>%&gt;
&lt;%<span class="mmm-code-submode"> end </span>%&gt;</pre>
<p>Agora, já temos todo o código necessário para realizar o <strong>cadastro de dados assíncrono</strong>, ou seja, <strong>inserção comum de dados em AJAX</strong>.</p>
<p>Mas há um problema, onde por razões de segurança não é permitido acesso a arquivos usando javascript (razoável não?). Desta forma, o upload de arquivos não irá funcionar em seu formulário.</p>
<p><strong>Passo 6: Usando iframes e responds_to_parent</strong></p>
<p>É esse o grande segredo de upload assíncrono no rails, ou seja, para burlar esta restrição do javascript, precisamos usar o  <a href="http://developer.apple.com/internet/webcontent/iframe.html">iframe remoting pattern</a>. Para fazer isto, basta inserir um iframe escondido em sua página e apontar o formulário para este iframe, usando target. O código de seu formulário da <code>index.rhtml</code> deve ser modificado para voltar a usar a tag <code>form_for</code>. Você deve estar se perguntando como será possível fazer upload assíncrono usando esta tag? Basta adicionar a extensão &#8220;.js&#8221; a action do formulário. Depois deixe o iframe do tamanho 1&#215;1 de forma a não aparecer na sua view.</p>
<p>Atenção: não use <code>display:none</code> pois dependendo do seu browser você esconderá não só do usuário o iframe, mas do browser também, fazendo com que este abra uma nova página.</p>
<pre>&lt;%<span class="mmm-code-submode"> form_for(:asset, :url =&gt;formatted_assets_path(:format =&gt; 'js'), :html =&gt; { :multipart =&gt; true, :target =&gt; 'upload_frame'}) do |form| </span>%&gt;
  &lt;%=<span class="mmm-output-submode"> render(:partial =&gt; '/assets/form', <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> bject =&gt; form) </span>%&gt;
&lt;%<span class="mmm-code-submode"> end </span>%&gt;
&lt;<span class="function-name">iframe</span> <span class="variable-name">id</span>='upload_frame' <span class="variable-name">name</span>=<span class="string">"upload_frame"</span> <span class="variable-name">style</span>=<span class="string">"width:1px;height:1px;border:0px"</span> <span class="variable-name">src</span>=<span class="string">"about:blank"</span>&gt;&lt;/<span class="function-name">iframe</span>&gt;</pre>
<p>Para lidar com o formulário no servidor, utilizaremos o plugin <a href="http://sean.treadway.info/responds-to-parent/">responds_to_parent</a>:</p>
<blockquote><p> script/plugin install http://responds-to-parent.googlecode.com/svn/trunk/</p></blockquote>
<p>Este plugin facilita o retorno do javascript à janela pai. Fazendo com que a resposta não ocorra dentro do próprio iframe, como seria o normal.</p>
<p>Para isto, apenas adicione o código abaixo na action <code>create</code> de seu controller:</p>
<pre>  <span class="comment-delimiter"># </span><span class="comment">POST /assets
</span>  <span class="comment-delimiter"># </span><span class="comment">POST /assets.xml
</span>  <span class="keyword">def</span> <span class="function-name">create</span>
    <span class="variable-name">@asset</span> = <span class="type">Asset</span>.new(params[<span class="constant">:asset</span>])
    respond_to <span class="keyword">do</span> |format|
      <span class="keyword">if</span> <span class="variable-name">@asset</span>.save
        flash[<span class="constant">:notice</span>] = <span class="string">'Asset was successfully created.'</span>
        format.html { redirect_to asset_url(<span class="variable-name">@asset</span>) }
        format.xml  { head <span class="constant">:created</span>, <span class="constant">:location</span> =&gt; asset_url(<span class="variable-name">@asset</span>) }
        format.js <span class="keyword">do</span>
          responds_to_parent <span class="keyword">do</span>
            render <span class="constant">:update</span> <span class="keyword">do</span> |page|
              page.insert_html <span class="constant">:bottom</span>, <span class="string">"assets"</span>, <span class="constant">:partial</span> =&gt; <span class="string">'assets/list_item'</span>, <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> bject</span> =&gt; <span class="variable-name">@asset</span>
              page.visual_effect <span class="constant">:highlight</span>, <span class="string">"asset_</span><span class="variable-name">#{@asset.id}</span><span class="string">"</span>
            <span class="keyword">end</span>
          <span class="keyword">end</span>
        <span class="keyword">end</span>
      <span class="keyword">else</span>
        format.html { render <span class="constant">:action</span> =&gt; <span class="string">"new"</span> }
        format.xml  { render <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ml</span> =&gt; <span class="variable-name">@asset</span>.errors.to_xml }
        format.js <span class="keyword">do</span>
          responds_to_parent <span class="keyword">do</span>
            render <span class="constant">:update</span> <span class="keyword">do</span> |page|
              <span class="comment-delimiter"># </span><span class="comment">update the page with an error message
</span>            <span class="keyword">end</span>
          <span class="keyword">end</span>
        <span class="keyword">end</span>
      <span class="keyword">end</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span></pre>
<p>A partir daqui, o arquivo <code>create.rjs </code>não é mais necessário.</p>
<p>Com estes passos, você já é capaz de fazer upload de arquivo de forma assíncrona, retornando os dados enviados em sua página instantâneamente.</p>
<p><strong>Passo 7: Configurando as respostas necessárias para um ambiente produtivo</strong></p>
<p>Para tornar a sua página pronta para ser utilizada por usuários comuns, é preciso fazer o seguinte:</p>
<ul>
<li>Manusear erros</li>
<li>Mostrar mensagem de erro quando o upload falha</li>
<li>Mostrar um retorno ao usuário &#8211; como um spinner (botão rotativo) &#8211; quando o arquivo é enviado e excluído.</li>
</ul>
<p>Atenção: Este passo é muito importante e não foi muito aprofundado no <a href="http://khamsouk.souvanlasy.com/2007/5/1/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent">tutorial original</a>, porém, pretendo pôr aqui as modificações que fiz para que eu obtivesse as respostas como propostas por ele.</p>
<p>Adicione ao lado do botão de submit uma imagem de spinner com <code>display:none</code>:</p>
<pre>&lt;%=<span class="mmm-output-submode"> submit_tag 'Criar', :class =&gt; "btn", <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> nclick =&gt; "Effect.Appear('spinner');" </span>%&gt; &lt;%=<span class="mmm-output-submode"> image_tag("spinner.gif", :id =&gt; 'spinner', :style =&gt; 'display:none;') </span>%&gt;</pre>
<p>Em cima de toda a marcação na partial <code>_form</code> adicione uma div vazia com o id=&#8221;error&#8221;:</p>
<pre>&lt;<span class="function-name">div</span> <span class="variable-name">id</span>=<span class="string">"error"</span>&gt;&lt;/<span class="function-name">div</span>&gt;</pre>
<p>Adicione as novas modificações na action create, o que fará com que ao obter sucesso no upload, oculte o spinner que foi ativado ao clicar no submit e esconda os erros que por ventura podem ter surgido. Em caso de erro, o spinner também é ocultado e é inserida uma mensagem de erro na div error.</p>
<pre>
  <span class="comment-delimiter"># </span><span class="comment">POST /assets
</span>  <span class="comment-delimiter"># </span><span class="comment">POST /assets.xml
</span>  <span class="keyword">def</span> <span class="function-name">create</span>
    <span class="variable-name">@asset</span> = <span class="type">Asset</span>.new(params[<span class="constant">:asset</span>])
    respond_to <span class="keyword">do</span> |format|
      <span class="keyword">if</span> <span class="variable-name">@asset</span>.save
        flash[<span class="constant">:notice</span>] = <span class="string">'Asset was successfully created.'</span>
        format.html { redirect_to asset_url(<span class="variable-name">@asset</span>) }
        format.xml  { head <span class="constant">:created</span>, <span class="constant">:location</span> =&gt; asset_url(<span class="variable-name">@asset</span>) }
        format.js <span class="keyword">do</span>
          responds_to_parent <span class="keyword">do</span>
            render <span class="constant">:update</span> <span class="keyword">do</span> |page|
              page.hide          <span class="string">'spinner'</span>
              page.hide          <span class="string">'error'</span>
              page.insert_html <span class="constant">:bottom</span>, <span class="string">"assets"</span>, <span class="constant">:partial</span> =&gt; <span class="string">'assets/list_item'</span>, <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> bject</span> =&gt; <span class="variable-name">@asset</span>
              page.visual_effect <span class="constant">:highlight</span>, <span class="string">"asset_</span><span class="variable-name">#{@asset.id}</span><span class="string">"</span>
            <span class="keyword">end</span>
          <span class="keyword">end</span>
        <span class="keyword">end</span>
      <span class="keyword">else</span>
        format.html { render <span class="constant">:action</span> =&gt; <span class="string">"new"</span> }
        format.xml  { render <span class="constant"> <img src='http://vebersol.net/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ml</span> =&gt; <span class="variable-name">@asset</span>.errors.to_xml }
        format.js <span class="keyword">do</span>
          responds_to_parent <span class="keyword">do</span>
            render <span class="constant">:update</span> <span class="keyword">do</span> |page|
              page.hide <span class="string">'spinner'</span>
              page.replace_html <span class="string">'error'</span>, <span class="string">"Houve um erro ao enviar os dados. Tente novamente."</span>
            <span class="keyword">end</span>
          <span class="keyword">end</span>
        <span class="keyword">end</span>
      <span class="keyword">end</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span></pre>
<p>Um bom link para excluir pode ser este, desta forma não é necessário o arquivo <code>destroy.rjs</code>:</p>
<pre>&lt;%=<span class="mmm-output-submode"> link_to_remote("X", :url =&gt; asset_path(asset),
                       :success  =&gt; " new Effect.Fade('asset-#{asset.id}')",
                       :failure  =&gt; "alert('Erro ao deletar.');\n" +
                                    "Element.hide('spinner-#{asset.id}');",
                       :loading  =&gt; "Element.show('spinner-#{asset.id}')",
                       :confirm  =&gt; "Tem certeza?", :method =&gt; :delete) </span>%&gt;
      &lt;%=<span class="mmm-output-submode"> image_tag("spinner.gif", :id =&gt; "spinner-"+asset.id.to_s,
          :style =&gt; 'display:none;') </span>%&gt;</pre>
<p><strong>Créditos:</strong></p>
<p>Tutorial original criado por <a href="http://khamsouk.souvanlasy.com">Khamsouk Souvanlasy</a><br />
Adaptado por <a href="http://www.awtres.com/">Vinícius Ebersol</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vebersol.net/2008/02/13/upload-de-arquivos-com-ajax-em-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

