Uma das dúvidas mais recorrentes de usuários do Paperclip é como tornar as bordas dos thumbnails arredondadas. Felizmente o Paperclip usa o ImageMagick para lidar com imagens e dá para passar opções para a linha de comando do convert:

1
2
3
4
5
6
7
8
9
has_attached_file :image, 
             :styles => { :thumb => ['400x300#', :png] },
             :convert_options => { 
                :thumb => "\\( +clone  -threshold -1 \
                     -draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0' \
                     \\( +clone -flip \\) -compose Multiply -composite \
                     \\( +clone -flop \\) -compose Multiply -composite \
                     \\) +matte -compose CopyOpacity -composite"
                }

Não esqueça que a imagem resultante será um PNG, então você precisa passar o formato na definição do thumb. Essas opções também funcionam no ImageMagick diretamente na linha de comando.

O resultado é esse:

Confira outras opções do ImageMagick.

Photo:Ange Soleil (a.k.a Tweng)

Frequentemente fazemos Page Cache na DBurns, para melhorar a performance das nossas aplicações. Um dos problemas que temos enfrentado nos últimos projetos é limpar o cache de outros models, quando modificamos alguma página no nosso CMS, principalmente quando temos um submenu dinâmico, com as filhas de uma página.

Digamos que temos um model Page e um model NewsArticle. Quando alteramos alguma coisa no Page queremos limpar o cache, através de um sweeper, tanto de Page como de NewsArticle.

Todas as soluções que encontramos, entre elas o tutorial de cache do Rails Envy, diziam para mudar o diretório de cache e apagá-lo por inteiro. Veja no tutorial mais detalhes de como fazer isso.

Só que o problema é que tanto o Mongrel quanto o Apache não sabem ler o cache se não for o padrão (em /public). Então você precisaria fazer um patch no Mongrel e uma mudança no httpd.conf do Apache:

1
2
3
4
5
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^/$ /cache/index.html [QSA,L]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /cache/$1.html [QSA,L]

OK, fácil, mas nem sempre temos acesso às configurações do Apache em produção, e por .htaccess não funciona, já tentamos. Para não depender do servidor onde fazemos deploy, a solução foi usar o mesmo procedimento (apagar o diretório inteiro), só que usando o diretório padrão de cache.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class PageSweeper < ActionController::Caching::Sweeper
  observe Page

  def after_save(page)
    clear_page_cache
  end

  def after_destroy(page)
    clear_page_cache
  end

  def clear_page_cache
    expire_page('/index')
    dirs = %w{ pages news }
    dirs.each do |dir|
      cache_dir = RAILS_ROOT + "/public/#{dir}"
      FileUtils.rm_r(Dir.glob(cache_dir+"/*")) rescue Errno::ENOENT
      RAILS_DEFAULT_LOGGER.info("Cache directory '#{cache_dir}' fully swept.")
    end
  end

end

Fiz isso, daí o Marcio Trindade deu a idéia de transformar em um método e colocar numa lib, adicionando o método ao ActionController::Caching::Sweeper. Daí poderíamos aproveitar para outros sweepers. Foi o que eu fiz, colocando o arquivo em config/initializers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module ActionController
  module Caching

    class Sweeper

      def sweep_directory(dirs)
        dirs.each do |dir|
          cache_dir = RAILS_ROOT + "/public/#{dir}"
          FileUtils.rm_r(Dir.glob(cache_dir+"/*")) rescue Errno::ENOENT
          RAILS_DEFAULT_LOGGER.info("Cache directory '#{cache_dir}' fully swept.")
        end
      end

    end

  end
end

E o sweeper ficou:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class PageSweeper < ActionController::Caching::Sweeper
  observe Page

  def after_save(page)
    clear_page_cache
  end

  def after_destroy(page)
    clear_page_cache
  end

  def clear_page_cache
    expire_page('/index')
    dirs = %w{ pages news }
    sweep_directory(dirs)
  end

end

Finalmente, saiu! O Carlos Brando acabou de anunciar o lançamento da versão 1.0 de “O (comovente) guia de Ruby do Why”, que é a tradução do “Why’s (poignant) guide to Ruby”.

Ajudei na tradução nos estágios iniciais, fiz algumas revisões, mas o trabalho pesado, da revisão final, foi do agaelebe, que também faz parte do Guru-SP.

O livro ensina a programar em Ruby, mas de uma forma muito descontraída e com várias historinhas. Fora que o Why the lucky stiff é um artista, então há várias tirinhas e desenhos, o que torna o aprendizado mais lúdico.

A versão em HTML do livro pode ser encontrada aqui.

Aproveitem!

No dia 4 de abril de 2009 acontecerá mais um evento relacionado a Ruby e Rails em São Paulo. O evento, ‘Ruby e Rails no Mundo Real’, é organizado pelo Guru-SP e com o apoio da Tempo Real Eventos, Sun e Caelum.

Haverá palestras sobre aplicações Ruby e Rails no ‘mundo real’, ou seja, coisas que estão no ar em produção, experiências reais. Vai além das ‘palestras tutoriais’.

Confira a programação e os palestrantes:

08:30 as 09:00: Credenciamento

09:00 as 09:15: Abertura do evento

09:15 as 10:30: Criando um Instant Messenger usando Rails (Vinícius Baggio)

10:30 as 10:45: Ruby, Rails e empreendedorismo (Hugo Lima Borges)

10:45 as 11:00: Coffee break

11:00 as 12:00: Ruby Desktop (Marcelo Castellani)

12:00 as 13:00: Almoço

13:00 as 14:00: Outsorcing, ou como trabalhar para empresas gringas (Caffo)

14:00 as 15:00: GlassFish on Rails: Escalabilidade e Confiabilidade (Maurício Leal – Sun Microsystems)

15:00 as 16:00: Só os imaturos não testam (Carlos Brando)

16:00 as 16:15: Coffee break

16:15 as 16:30: O que é e como funciona o RubyLearning (Willian Molinari)

16:30 as 17:30: Ruby, muito mais do que reflexivo! (Fábio Kung)

17:30 as 18:00: Desconferência e Encerramento

Será realizado no Century Flat Paulista, na Rua Teixeira da Silva, 647, perto do metrô Brigadeiro.

A inscrição custa R$69 (até 31/03) e pode ser feita na página oficial do evento.

O Paperclip consegue fazer thumbnail da primeira página de um PDF. Para isso, escreva:


has_attached_file :pdf, :styles { :thumb => "100x200#" }

como você faz para qualquer imagem. Porém, além de ter o ImageMagick instalado, você vai precisar também instalar o GhostScript, que é a biblioteca para interpretar e salvar PDFs. Senão você vai ter erros como o seguinte:

1
2
3
An error was received while processing: #<Paperclip::NotIdentifiedByImageMagickError: 
/var/folders/xz/xz9+JOHXHse6kcOo1B2kMk+++TI/-Tmp-/stream.29062.0 
is not recognized by the 'identify' command.>

que é o mesmo erro que acontece quando você não tem o ImageMagick instalado, ou o Paperclip não consegue achar. Escrevi sobre isso neste post. Para testar se você tem o GhostScript instalado, faça:


identify -format "%wx%h" algumarquivo.pdf

Se der erro de arquivo não encontrado, você precisa instalar o GhostScript:

1
2
3
4
5
# Leopard
sudo port install ghostscript

# Ubuntu
sudo apt-get install ghostscript

Teste de novo e o comando supracitado deverá retornar a largura e altura do PDF.

#fikdik