Ruby com XMPP: descobrindo o status dos seus contatos

Havia prometido no meu últmo post que mostraria como fazer aplicações Web em tempo real usando XMPP.

Vou pedir um pouco de paciência para vocês, pois esqueci de colocar um conceito importante usado em qualquer cliente Jabber: o status dos seus contatos, para saber quem está on-line (available), off-line, away ou ocupado (do not disturb).

O código é muito simple, veja:

presence.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env ruby

require 'rubygems'
requirespan> 'xmpp4r'

# initial statement: connecting and login
client = Jabber::Client.new(Jabber::JID.new('neo@localhost/Home'))
client.connect('localhost', '5222')
client.auth('123456')
client.send(Jabber::Presence.new.set_type(:available))
# the code line below you change status:
# ":chat" for available, ":away" for away or ":dnd" for do not disturb
client.send(Jabber::Presence.new(:chat, 'Buddies presence!'))

# callback for incoming presence messages
# the "message" object has many methods, below, at this simple example,
# I'm using only four:
# - from: user who has just changed his/her status
# - type: if "unavaliable" the user quited from Jabber
# - show: online user is "away" or "do not distub"
# - status: user information "What are you doing now?"
client.add_presence_callback do |message|
 
  from = (!message.status.nil? && message.status.to_s != '') ? "#{message.from} - (#{message.status})" : message.from
 
  if !message.type.nil? && message.type.to_s == 'unavailable'
    puts "#{from} - is off-line"
  elsif !message.show.nil? && message.show.to_s == 'away'
    puts "#{from} - is \"away\" now"
  elsif !message.show.nil? && message.show.to_s == 'dnd'
    puts "#{from} - is \"do not disturb\" now"
  else
    puts "#{from} - is available now"
  end

end

main_thread = Thread.new {
  while true do
  end
}

main_thread.join

@client.close

Importante: pra mudar o status via Ruby veja o comentário acima da linha 13 do script.

 

Executando o script

 

 shell> ruby presence.rb

 

 

Podemos agora brincar com o cliente Jabber mudando o status do usuário e veremos as saídas do script presence.rb

1) Conectando no Jabber

 

Usuário conectado ao Jabber

Usuário conectado ao Jabber



 

 

2) Mudando para o estado de Ocupado (Do Not Disturb)

 

Note que aqui vou adicionar ao status a frase “Hard work!”

 

Mudando o status para ocupado dizendo "Hard work!"

Usuário mudou seu status para ocupado dizendo 'Hard work!'



 

 

3) Mudando para o estado de Ausente (Away)

 

Note que aqui vou adicionar ao status a frase “On the phone!”

 

Mudando o status para ocupado dizendo "Hard work!"

Usuário mudou seu status para ausente (away) dizendo 'On the phone!'



 

 

4) Mudando para o estado de Disponível (Available)

 

Note que aqui vou adicionar ao status a frase “Free for chat”

 

Usuário mudou seu status para Disponível (avalilable) dizendo 'Free for chat'

Usuário mudou seu status para Disponível (avalilable) dizendo 'Free for chat'



 

 

5) Desconectando do Jabber (Off-line)

 

Usuário desconectou do Jabber (Offline)

Usuário desconectou do Jabber (Offline)



 

 

Enfim, chegamos ao fim dos posts sobre o básico de Ruby com XMPP.

O que aprendemos?

Com esse conhecimento podemos ir com uma bagagem mais completa para desenvolver aplicações Web em tempo real, utilizando apenas JavaScript e o protocolo XMPP

Deixe seu comentário e até a próxima!

Ruby com XMPP Filetransfer: enviando e recebendo arquivos

Este é meu segundo post sobre como usar Ruby com o protocolo XMPP. No primeiro descrevi como enviar e receber mensagens com Ruby e XMPP, agora irei mostrar como enviar arquivos de um cliente Jabber para um outro.

Antes de começar gostaria de informar que vamos utilizar os mesmos recursos de servidor Jabber e usuários já configurados no meu primeiro artigo desta série. A novidade aqui fica por conta do código. Iremos começar pelo cliente que ficará encarregado de receber os arquivos.

O script receiver.rb vai instanciar a classe ReceiveFile do arquivo receive_file.rb que faz toda a reponsabilidade do recebimento.

receiver.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env ruby

require 'rubygems'
require 'xmpp4r'
require 'receive_file'

client = Jabber::Client.new(Jabber::JID.new('neo@localhost/Home'))
client.connect('localhost', '5222')
client.auth('123456')
client.send(Jabber::Presence.new.set_type(:available))
client.send(Jabber::Presence.new(:chat, 'Files Transfer!'))

receive_file = ReceiveFile.new
receive_file.wating_for_incoming(client, '/tmp')

receive_file.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
require 'xmpp4r/bytestreams'

class ReceiveFile
  def wating_for_incoming(client = nil, destination_dir = nil)
    @file_transfer = Jabber::FileTransfer::Helper.new(client)
    receive_file_callback(destination_dir)
    puts "Waiting for incoming files..."
    Thread.stop
  end

  private
  def receive_file_callback(destination_dir = nil)
    @file_transfer.add_incoming_callback do |iq, file|
      puts "Incoming file transfer from #{iq.from}: #{file.fname} (#{format_file_size(file.size)})"
      filename = "#{destination_dir}/#{file.fname.split(/\//).last}"
      file_offset = check_incoming_file_offset(iq, file, filename)

      Thread.new {
        begin
          puts "Accepting #{file.fname}"
          @stream = @file_transfer.accept(iq, file_offset)
          if @stream.kind_of?(Jabber::Bytestreams::SOCKS5Bytestreams)
            @stream.connect_timeout = 60
            add_stream_callback
          end
          handle_receiving(filename, file_offset)
        rescue Exception => exception
          puts "#{exception.class}: #{exception}\n#{exception.backtrace.join("\n")}"
        end
      } # Thread
    end
  end

  def check_incoming_file_offset(iq = nil, file = nil, filename = nil)
    file_offset = nil
    if File::exist?(filename)
      puts "#{filename} already exists"
      if (File::size(filename) < file.size) && (file.range)
        file_offset = File::size(filename)
        puts "Peer supports <range/>, will retrieve #{file.fname} starting at #{file_offset}"
      else
        puts "#{file.fname} is already fully retrieved, declining file-transfer"
        @file_transfer.decline(iq)
      end
    end
   
    return file_offset
  end
 
  def add_stream_callback
    @stream.add_streamhost_callback do |streamhost, state, exception|
      case state
        when :connecting
          puts "Connecting to #{streamhost.jid} (#{streamhost.host}:#{streamhost.port})"
        when :success
          puts "Successfully using #{streamhost.jid} (#{streamhost.host}:#{streamhost.port})"
        when :failure
          puts "Error using #{streamhost.jid} (#{streamhost.host}:#{streamhost.port}): #{exception}"
      end
    end  
  end

  def handle_receiving(filename = nil, file_offset = nil)
    puts "Waiting for stream configuration..."
    if @stream.accept
      puts "Stream established"
      outfile = File.new(filename, (file_offset ? 'a' : 'w'))
      while buf = @stream.read
        break if buf.nil? || buf == ''
        outfile.write(buf)
        print '.'
        $stdout.flush
      end
      puts '!'
      outfile.close
      @stream.close
    else
      raise 'Stream failed'
    end
  end
 
  def format_file_size(bytes_size = 0)
    kilo_bytes_size = bytes_size / 1024
    return "#{(kilo_bytes_size.to_i == 0) ? bytes_size.to_s + ' B' : kilo_bytes_size.to_s + ' KB' }"
  end
end

Agora execute o receiver.rb:

 shell> ruby receiver.rb
 Waiting for incoming files. . .

Neste momento ele está esperando que alguém envie um arquivo. Vamos agora aprender como enviar um arquivo, de acordo com o código que se segue.

Aqui utilizei o mesmo principio do receiver: o sender.rb instancia a classe SendFile do arquivo send_file.rb.

sender.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env ruby

require 'rubygems'
require 'xmpp4r'
require 'send_file'

client = Jabber::Client.new(Jabber::JID.new('acc@localhost/Home'))
client.connect('localhost', '5222')
client.auth('123456')
client.send(Jabber::Presence.new.set_type(:available))
client.send(Jabber::Presence.new(:chat, 'Files Transfer!'))

send_file = SendFile.new
status = send_file.send(client, 'neo@localhost/Home', '/home/acc/document.txt')

send_file.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
require 'xmpp4r/bytestreams'

class SendFile
  def send(from = nil, to = nil, filename = nil)
    begin
      file_transfer = Jabber::FileTransfer::Helper.new(from)
      @source = Jabber::FileTransfer::FileSource.new(filename)
      puts "Offering #{@source.filename} to #{to}"
      @stream = file_transfer.offer(Jabber::JID.new(to), @source)
      return handler_stremam
    rescue Exception => exception
      raise exception.to_s
    end
  end
 
  private  
  def handler_stremam
    if @stream
      stream_callback
      @stream.open      
      if @stream.kind_of? Jabber::Bytestreams::SOCKS5BytestreamsInitiator
        puts "Using streamhost #{@stream.streamhost_used.jid} (#{@stream.streamhost_used.host}:#{@stream.streamhost_used.port})"
      end

      puts 'Stream established'
      while buf = @source.read
        print '.'
        $stdout.flush
        @stream.write buf
        @stream.flush
      end
      puts '!'
      @stream.close
      return true
    else
      puts 'Error while hadling stream!'
      return false
    end
  end
 
  def stream_callback
    if @stream.kind_of? Jabber::Bytestreams::SOCKS5BytestreamsInitiator
      @stream.add_streamhost(socket_server)
     
      # TODO: Proxy configuration
      ([]).each { |proxy|
        @stream.add_streamhost proxy
      }

      @stream.add_streamhost_callback { |streamhost, state, exception|
        case state
          when :connecting
            puts "Connecting to #{streamhost.jid} (#{streamhost.host}:#{streamhost.port})"
          when :success
            puts "Successfully using #{streamhost.jid} (#{streamhost.host}:#{streamhost.port})"
          when :failure
            puts "Error using #{streamhost.jid} (#{streamhost.host}:#{streamhost.port}): #{exception}"
        end
      }
    end
  end

  def socket_server
    # TODO: Socket configuration
    puts 'Biding Local server: locahost:#65010'
    begin
      bss = Jabber::Bytestreams::SOCKS5BytestreamsServer.new('65010')
      bss.add_address('localhost')      
      return bss
    rescue Exception => exception
      raise exception.to_s
    end
  end
 
end

Agora basta executar o sender.rb que a transferência de arquivos começará, de acordo com o output abaixo:

 shell> ruby sender.rb
 Offering document.txt to neo@localhost/Home
 Biding Local server: locahost:#65010
 Successfully using acc@localhost/Home (localhost:65010)
 Using streamhost acc@localhost/Home (localhost:65010)
 Stream established
 ……………….!

Voltando ao shell do receiver.rb teremos o seguinte output:

 shell> ruby receiver.rb
 Waiting for incoming files…
 Incoming file transfer from acc@localhost/Home: document.txt (53 kB)
 Accepting document.txt
 Waiting for stream configuration…
 Connecting to acc@localhost/Home (127.0.0.1:65010)
 Successfully using acc@localhost/Home (127.0.0.1:65010)
 Stream established
 .!

Pronto! Veja agora que existe um arquivo transferido da sua pasta de origem até a sua pasta de destino.

Xmpp4r no Windows

O Xmpp4r apresenta problema ao transferir arquivos binários a partir de máquinas Windows. Para resolver este problema abra para edição o arquivo:

 C:\Ruby\lib\ruby\gems\1.8\gems\xmpp4r-0.5\lib\xmpp4r\bytestreams\helper\filetransfer.rb

Procure no código o método initialize da classe FileSource e mude a seguinte linha de:

1
@file = File.new(filename)

para:

1
@file = File.open(filename, 'rb')

Salve, feche o arquivo e teste a transferẽncia.

Bom pessoal, este é o segundo post sobre como utilizar Ruby com XMPP. O terceiro vou mostrar como fazer aplicações web em tempo real usando as mesmas ferramentas. Até lá!

Ruby com XMPP enviando e recebendo mensagens

Este é o primeiro post de uma série que pretendo publicar sobre como usar Ruby e o XMPP, protocolo utilizado pelo Google Talk e outros servidores Jabber (que há pouco foi adiquirido pela Cisco).

Primeiramente vou instalar um servidor Jabber, escolhi o Openfire, porém, fique a vontade para instalar qualquer servidor que você queira.

Para fazer o download do Openfire clique aqui.

 

Na interface WEB do Openfire criei alguns usuários, todos dentro de um mesmo grupo chamado test

Criando usuários no Openfire

Criando usuários no Openfire

Importante: todos os usuário aqui, neste exemplo, estão com a senha 123456. Em sistemas que estejam em produção NUNCA faça isso!

Neste exemplo vou utilizar o Pidgin como interface gráfica para ajudar na explicação, mas, novamente, fique a vontade para utilizar qualquer outro aplicativo do gênero.

Caso você não tenha o Pidgin instalado:

 

 shell> sudo apt-get install pidgin

 

 

Com o Pidgin instalado, vou configurá-lo para conectar-me com o usuário: acc

Configurações básicas do Pidgin

Configurações básicas do Pidgin

Configurações avançadas do Pidgin

Configurações avançadas do Pidgin

Vamos agora instalar a gem do Ruby que será sua interface com o XMPP: xmpp4r

 

 shell> sudo gem install xmpp4r

 

 

Feito isso já temos a infra-estrutura pronta para desenvolvermos nosso código.

Este exemplo, abaixo, mostra como funciona o recebimento de mensagem e de envio. O que ele faz basicamente é: ao receber uma mensagem de um outro cliente qualquer via Pidgin, GAIM, IChat, PSI ou mesmo outro cliente que você desenvolveu, ele processa e de acordo com o que foi recebido ele envia uma mensagem de retorno específica. Vejamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env ruby

require 'rubygems'
require 'xmpp4r'

# Sends to a specific one an arbitrary text message
def my_send_message(body = nil)
  to_jid = Jabber::JID.new('acc@localhost/receive')
  message = Jabber::Message::new(to_jid, body).set_type(:chat)
  @client.send(message)
end

# Process the incoming message body and returns what it is
def process_body(body)
  if body.nil? || body == ''
    nil
  elsif body.match(/\d+/)
    'Number'
  elsif body.downcase.match(/^[aeiou]{1}$/)
    'Vowel'
  elsif body.length == 1
    'Consonant'
  elsif body.downcase == 'quit'
    @quit = span class="kw2">true
    nil
  elsif body.split(/\s/).size > 1
    'Phrase'
  else
    'Word'
  end
end

@quit = false

# Connect to Jabber server. The neo@localhost/Home means:
# 'node'@'domain'/'resource'
# node: user ID
# domain: What organization user is part
# resource: Where user is; work, home, coffee, restaurant ...
@client = Jabber::Client.new(Jabber::JID.new('neo@localhost/Home'))
@client.connect('localhost', '5222')
@client.auth('123456')
@client.send(Jabber::Presence.new.set_type(:available))

# Adding threaded callback, dispatched on every  new incoming
# message
@client.add_message_callback do |message|
  begin
    response = process_body(message.body)
    unless response.nil?
      puts "Message from #{message.from}: #{message.body}"
      puts "Response: #{response}"
      puts '---'
      my_send_message(response)
    end
  rescue Exception => exception
    puts exception.to_s
  end
end

# HACK: this thread is just to keep the application running.
# When the "quit" message arrives the @quit variable is setted
# to "true". So, it closes the thread, also closes the user
# connection and finishes the application gracefully.
main_thread = Thread.new {
  while !@quit do
  end
}
main_thread.join

@client.close
puts 'Bye'

Salve o código ruby acima e execute-o:

 

 shell> ruby auto_chat.rb

 

 

Observe agora seu cliente gráfico (Pidgin?)

Usuário conectado

Usuário conectado

Abra uma janela com o usuário online, começe o enviar mensagens e veja as respostas automáticas do código ruby que fizemos:

Chat de respostas automáticas com Ruby e XMPP

Chat de respostas automáticas com Ruby e XMPP

Instalando Ruby, Rails, Mysql, Cucumber e outros no Ubuntu

Gostaria de contribuir mostrando uma maneira prática de como montar seu ambiente de desenvolvimento Ruby on Rails, para quem instalou o Linux Ubuntu (qualquer que seja a versão),

O primeiro passo é atualizar seu sistema operacional e adicionar bibliotecas úteis ao ambiente Ruby:

shell> sudo apt-get update
shell> sudo apt-get dist-upgrade
shell> sudo apt-get install build-essential

Instale o ruby e seus utilitários:

shell> sudo apt-get install ruby ri rdoc ruby-dev irb libopenssl-ruby

Tendo o Ruby instalado, agora, coloque o Rubygem mais atualizado:

shell> wget -c http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz
shell> tar xfvz rubygems-1.3.5.tgz
shell> cd rubygems-1.3.5/
shell> sudo ruby setup.rb
shell> sudo ln -s /usr/bin/gem1.8 /usr/bin/gem

Importante I:
Quando publiquei este material a versão mais nova do Rubygem era a 1.3.5, por causa disso, é bom verificar no seu site de releases se já existe uma versão mais nova.

Instalando o Rails e o Mogrel:

shell> sudo gem install rails
shell> sudo gem install mongrel

Instale os Bancos de Dados Mysql e Sqlite3 com suas bibliotecas para integra-los com o Ruby:

shell> sudo apt-get install mysql-server
shell> sudo apt-get install libmysqlclient-dev
shell> sudo gem install mysql
shell> sudo apt-get install sqlite3
shell> sudo apt-get install libsqlite3-ruby

Instalando o Git:

shell> sudo apt-get install git-core

Instalando frameworks de testes:

shell> sudo gem install rspec
shell> sudo gem install rspec-rails
shell> sudo gem install cucumber
shell> sudo apt-get install libxslt1-dev
shell> sudo gem install webrat

Instalando o RMagick:

shell> sudo apt-get install libmagick9-dev
shell> sudo gem install rmagick

Essas gems abaixo são as que mais utilizo no meu dia-a-dia, fica a seu critério instalar ou não:

shell> sudo gem sources –add http://gems.github.com/
shell> sudo gem install wirble
shell> sudo gem install hpricot
shell> sudo gem install hoe
shell> sudo apt-get install libcurl4-openssl-dev
shell> sudo gem install curb

Espero que os ajudem a perder tempo montando seu ambiente e que seu tempo se transforme em desenvolver novas ferramentas e ajudar a comunidade Ruby on Rails a crescer.

Ruby on Rails com Mongo Mapper e Restful Authentication

Neste post vou mostrar a vocês minha experiência utlizando Ruby on Rails com o MongoDB.

Dentre várias gems para interagir com o MongoDB escolhi o mongo_mapper. Estudei algumas opções e esta foi a mais completa e bem fácil de usar. Uma descoberta interessante é que o plugin restiful_authentication funciona muito bem (diria até que perfeitamente) com essa tecnologia de armazenamento de dados, porém é necessário mudar umas coisinhas como vou demonstrar aqui.

Primeiro instale o driver de Ruby para o MongoDB:

shell> sudo gem install mongo_ext

Em seguida instale a gem do mongo_mapper:

shell> sudo gem install mongo_mapper -s http://gemcutter.org

Feito isso vamos criar um projeto Rails e configurar sua aplicação para usar o MongoDB:

shell> rails mongo_app
shell> cd mongo_app

Edite o arquivo config/environment.rb e adicione as seguintes linhas:

1
2
3
4
5
6
7
8
Rails::Initializer.run do |config|
  ...
  config.gem 'mongo_mapper', :version => '>= 0.6.4'
  config.frameworks -= [ :active_record ]
  ...
end

MongoMapper.database = "mongo_app-#{RAILS_ENV}"

Chegando aqui já temos uma aplicação Rails configurada para usar o MongoDB. Todavia, como dito antes, vamos utilizar ainda o plugin restful_authentication neste contexto. Assim sendo:

shell> cd vendor/plugins
shell> git clone git://github.com/technoweenie/restful-authentication.git restful_authentication
shell> cd ../../
shell> ruby script/generate authenticated user sessions

Importante I:
Note aqui que não usei a opção –skip-migration onde mais abaixo explicarei o porquê.

Daqui já temos os recursos que precisamos faltando apenas mudar um pouco as coisas.

Como não usaremos mais o ActiveRecord edite o arquivo app/model/user.rb substituindo:

1
2
class User < ActiveRecord::Base
...

por

1
2
3
4
5
6
7
8
9
10
11
12
class User
  include MongoMapper::Document

  key :name, String
  key :login, String
  key :email, String
  key :crypted_password, String
  key :salt, String
  key :remember_token, String
  key :remember_token_expires_at, DateTime
  timestamps! # columns "created_at" and "updated_at" both DateTime
  ...

Importante II:

Não adicione a coluna “id” pois esta será usada pelo MongoDB através da coluna “_id” criada por ele automaticamente.

Importante III:

Dependendo de como você usou o plugin restful_authentication talvez seja necessário adicionar algumas outras colunas. Veja no migration de user se todas as colunas de lá estão mapeadas no seu novo model. Feito isso sugiro fortemente que apaque o migration:

shell> rm -f db/migrate/XXXXXXXXXXXXXX_create_users.rb

Agora comente ou apague a linha do attr_accessible do model de user:

1
# attr_accessible :login, :email, :name, :password, :password_confirmation

Pronto, é isto!

Tabelas temporárias no MySQL

Traduzindo fielmente o que tem na referência do MySQL: "Você pode usar o palavra chave TEMPORARY ao criar uma nova tabela. Uma tabela TEMPORARY é visível apenas na conexão que a criou, e é destruída automaticamente quando a conexão for terminada. Isto significa que duas conexões pode usar tabelas temporárias com mesmo nome sem conflito uma com a outra ou com uma tabela já existente não-temporária do mesmo nome. (A tabela já existente fica escondida até que a tabela temporária seja destruída). Para criar tabela temporária, você tem que ter privilégio de CREATE TEMPORARY TABLES"[1]

Ou seja, se uma conexão “A” criar um tabela temporária `temp` essa tabela só existe para essa conexão. Se uma conexão “B” é estabelecida, para “B” a tabela temporária `temp` não existe.

Se “B” criar a mesma tabela temporária `temp` de “A”, “B” não consegue exergar os dados de “A” e nem “A” consegue exergar os dados de “B”.

Exemplos: Neste, utilizo a mesma database com o mesmo username e password.

Conexão “A”
——————

mysql> CREATE TEMPORARY TABLE `temp` (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255));
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO temp (name) VALUES (’Adilson’);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM temp;
+----+---------+
| id | name |
+----+---------+
| 1 | Adilson |
+----+---------+
1 row in set (0.00 sec)

Conexão “B”
——————

mysql> SELECT * FROM temp;
ERROR 1146 (42S02): Table ‘test.temp’ doesn’t exist

mysql> CREATE TEMPORARY TABLE `temp` (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255));
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM temp;
Empty set (0.00 sec)

mysql> INSERT INTO temp (name) VALUES (’Chacon’);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM temp;
+----+--------+
| id | name |
+----+--------+
| 1 | Chacon |
+----+--------+
1 row in set (0.00 sec)

Quando cada conexão for destruída, as suas respectivas tabelas temporárias, automaticamente, também, serão destruídas.

Há problemas/limitações relacionados com tabelas temporárias [2], dentre eles:

  • Não aparecem no “SHOW TABLES”
  • Não podem ser renomeadas

[1] MySQL Craete Table Reference
[2] MySQL Temporary Table Problems

Plugin Globalize: Localized Views

Uma das funcionalidades do plugin Globalize para Rails é a tradução de views (ou templates). Há duas formas para a tradução.

A primeira maneira é a tradução string por string, por exemplo, ‘Wellcome’ torna-se ‘Bem-vindo’, ‘Page’ torna-se ‘Página’ e assim por diante. Para isso, o plugin Globalize, requer que você cadastre a tradução da palavra. Veja como funciona:

Execute o ‘ruby script/console‘ e lá faça assim:

1
2
3
Locale.set('pt-BR')
Locale.set_translation('Wellcome', 'Bem-vindo')
Locale.set_translation('Page', 'Página')

Depois, numa view faça:

1
2
3
<% Locale.set_locale('pt-BR') %>
'Wellcome'.t # => 'Bem-vindo'
'Page'.t # => 'Página'

Desta forma, dependendo da quantidade de palavras utilizadas, muitas consultas ao banco poderão ser realizadas e isto pode se tornar um gargalo na sua aplicação.

Uma outra maneira de atacar este problema é criar (e manter) uma view para cada linguagem, ou seja, tendo a view padrão, por exemplo index.html.erb, você criaria o index.html.<lang>.erb, onde o <lang> é a liguagem utilizada de acordo com o Locale.set(”<lang>”).

<lang> View
pt-BR  index.html.pt-BR.erb
es-ES  index.html.es-ES.erb
fr-FR  index.html.fr-FR.er

 

A desvantagem desta abordagem é que você teria vários templates para manter, ou seja, uma alteração em uma view, provavelmente, as demais, também, terão de ser modficadas.