Você ama a Ruby?

Mostre ao mundo sua paixão pela Ruby, começando com a capa do Facebook.

domingo, 3 de agosto de 2014

"Service oriented design with ruby and rails" fix para o capítulo 1

Postado por DoctorRu (Will)

Atualmente estou lendo o livro Service oriented design with ruby do Paul Dix, apesar de ainda estar no primeiro capítulo o livro parece ser ótimo porém por ser de 2010 está desatualizado em alguns aspectos principalmente no que tange ao RSpec.

Amazon

Ao realizar os testes ocorrem diversos erros e "warnings" dada a novas versões do Ruby e gems utilizadas, atualizei a sintaxe necessária e inclui um parâmetro de configuração do ActiveRecord que resolvem os problemas do primeiro capitulo.

A atualização mais importante é a inclusão desta linha no arquivo services.rb
ActiveRecord::Base.include_root_in_json = true
Com isto o nome do Hash gerado pelo JSON.parse é incluido na saída JSON, caso contrário ao tentar executar a seguinte linha:
attributes = JSON.parse(last_response.body)["user"]
Ocorrerá uma falha de teste pois o Hash retorna apenas os atributos:
{"id":1,"name":"paul","email":"paul@pauldix.net","bio":"rubyist"}
Quando o esperado é:
{"user":{"id":1,"name":"paul","email":"paul@pauldix.net","bio":"rubyist"}}
As outras alterações são referentes a sintaxe do RSpec, abaixo alguns exemplos na versão antiga e na versão atualizada do arquivo rspec/services_spec.rb
      # Old
      last_response.should be_ok
      attributes = JSON.parse(last_response.body)["user"]
      attributes["name"].should == "paul"

      # New
      expect(last_response).to be_ok
      attributes = JSON.parse(last_response.body)["user"]
      expect(attributes["name"]).to eq "paul"


      # Old
      last_response.should be_ok
      attributes = JSON.parse(last_response.body)["user"]
      attributes.should_not have_key("password")

      # New      
      expect(last_response).to be_ok
      attributes = JSON.parse(last_response.body)["user"]
      expect(attributes).not_to have_key("password")  

 
      # Old
      last_response.status.should == 404
  
      # New
      expect(last_response.status).to eq 404

Estou disponibilizado o código completo no meu GitHub 

sexta-feira, 19 de julho de 2013

Rails: Carregando constantes automaticamente

Postado por DoctorRu (Will)

Em outro post, de nome bem sugestivo Definindo método Initialize no controller sem destruir o layout expliquei como criar variáveis no método initialize sem comprometer o layout utilizando before_filter, aqui apresento uma maneira alternativa e mais recomendada para definir préviamente as constantes que venham a ser utilizadas em um projeto.

Arquivos criados no diretório initializers são carregados com as as outras configurações do Rails quando seu projeto é acessado no servidor, um ótimo lugar para definição de constantes.

Crie um arquivo com o nome desejado (irei utilizar site.rb) dentro do diretório initializers do seu projeto, como: raiz do projeto/config/initializers/site.rb e inclua as seguintes linhas:
#encoding:UTF-8
module Site

  CONFIG = {
    header:   "http://rubydoit.blogspot.com",
    footer:   "11 5555-5555 / 11 5555-5556 - São Paulo - Brasil"
  }

end
Acima foi criado um hash de nome CONFIG e dentro dele foram atribuídos chaves e valores para utilização dentro do seu código, como teste vou acessar o console do rails em modo sandbox (recomendando para testes pois todas as alterações sofrem rollback quando saímos do console).

Lembrando que é necessário especificar o namespace utilizando :: entre o nome do módulo e o nome do hash!
$ rails c --sandbox
Loading development environment in sandbox (Rails 3.2.13)
Any modifications you make will be rolled back on exit

irb(main):001:0> cabecalho = Site::CONFIG[:header]
=> "http://rubydoit.blogspot.com"

irb(main):002:0> rodape = Site::CONFIG[:footer]
=> "11 5555-5555 / 11 5555-5556 - São Paulo - Brasil"

Observação: Lembre-se de carregar o console a partir do diretório raiz do seu projeto.

Este post foi escrito ao som de Ibrahim Ferrer - Guaguanco callejero

terça-feira, 2 de julho de 2013

Ruby: Shell script para baixar a documentação da Ruby, instalar e restaurar links quebrados, automaticamente.

Postado por DoctorRu (Will)

Atenção: este script é apenas para linux.

Se você ja optou por baixar a documentação da Ruby no site Ruby-Doc.org e ao invés instalar os arquivos em um servidor web rodando localmente optou por salvar em algum diretório na sua home, você deve ter ficado um pouco frustrado ao ver todos os links de css e javascript quebrados, arrumar cinco ou seis páginas tudo bem, mas são centenas de arquivos.

Pensando neste problema resolvi fazer uma contribuição para a comunidade e criei um script que faz o download, instala e repara todos os links quebrados automaticamente (exceto os links para download e gems pois não vi necessidade).

A documentação baixada será a Core e Stand libs versão 1.9.3 pois ainda não foram disponibilizados os links oficiais para download da documentação da versão 2 compactada.

A edição de todos os arquivos html é um pouco demorada, por aqui foram quase 20 minutos de processamento, pois são feitas diversas alterações em muitos links.

Baixe o script para seu diretório home, torne o script executável com chmod +x install e execute-o com ./install após isso informe em qual diretório a documentação deverá ser instalada.

Caso tenha algum dúvida, encontre algum bug ou tenha achado o script útil, deixei um comentário!

Você pode baixar esse script no meu GitHub.

Trilha sonora deste post: Bomb The Bass - Beat Dis (Extended Dis)

terça-feira, 25 de junho de 2013

MySQL: Aumentando a segurança e configurando acesso remoto

Postado por DoctorRu (Will)

MySQL
Esse tutorial foi escrito para o Linux Ubuntu, se o seu sistema é outro então adapte este tutorial conforme sua necessidade, sempre verificando o path dos arquivos mencionados e criando uma cópia de segurança além de anotar as permissões dos mesmos antes de começar as alterações.

Por padrão é possível logar-se localmente em um servidor MySQL como usuário anônimo sem a necessidade de autenticação, apesar do acesso ficar restrito as bases test e information_schema, uma mente criativa pode através de script coletar dados da máquina e armazenar estes dados dentro da base test para futura consulta sem chamar a atenção.

Os parâmetros mais utilizados para conexão com o servidor são:
-u nome do usuário
-p requisição de senha
-h host / ip
-P porta de conexão (padrão 3306)
-D base de dados

Observação: Apesar de apontarem para o mesmo local,  no servidor,  localhost e 127.0.0.1 são vistos como coisas diferentes, então um usuário que tem acesso a localhost não necessariamente conseguirá logar em 127.0.0.1, ou seja, dentro da base mysql na tabela user localhost é uma coisa e 127.0.0.1 é outra, ja no arquivo my.conf usa-se apenas 127.0.0.1 quando se fala de acesso local.

Tornando o MySQL um pouco mais seguro

 Para solucionar a questão do login temos três possíveis soluções.

  • Criar uma senha para o usuário anônimo
  • Remover o usuário anônimo (identificado como '' na tabela user)
  • Deletar a base test
Optei por criar uma senha forte para o usuário anônimo  ao invés de deletá-lo ou de deletar a base test  pois ambos podem ser úteis no futuro, assim você não precisa se dar o trabalho de criar uma nova conta ou tabela caso precise de algo corriqueiro e dificilmente alguém tentará crackear a senha de usuário com  privilégios restritos apenas para salvar dados na base, mas se a senha for nula essa técnica pode ser válida.

Conecte-se como  root no servidor através do ip 127.0.0.1 ou localhost
$ mysql -u root -p -h 127.0.0.1 -D mysql
Altere a senha do usuário anônimo que é identificado como ''@'localhost' substituindo o respectivo texto pela nova senha.
mysql>SET PASSWORD FOR ''@'localhost' = password('nova senha');
Query OK, 0 rows affected (0.00 sec)
Para testar basta sair do servidor e se conectar como anônimo informando a nova senha, lembre-se de utilizar o parâmetro -p
mysql>exit
Bye

$ mysql -p -h 127.0.0.1 
Password: 
Para evitar logins remotos (ip's externos), procure a seguinte linha no arquivo  /etc/mysql/my.conf (este é o path relativo para distro ubuntu, caso não encontre o arquivo procure-o através do comando locate ou find)
skip-networking
Ao encontrá-la, descomente-a retirando o # da frente do comando, caso essa linha não exista, crie-a.

Certifique-se de que no mesmo arquivo a linha abaixo contém o IP local 127.0.0.1 ao invés de 0.0.0.0 assim apenas conexões locais serão aceitas
bind-address        = 127.0.0.1
Pronto! Menos uma questão de segurança para se preocupar.
Se você pretende habilitar acesso remoto, siga as instruções abaixo, caso contrário "por hoje é só pessoal!"

Habilitando acesso remoto

Atenção: Aqui será feito exatamente o contrário de parte do que fizemos acima! Pois vamos liberar o acesso remoto ao invés de bloqueá-lo, porém de uma forma segura.

O primeiro passo é garantir a algum usuário permissão para conectar ao servidor e especificar quais serão seus privilégios, abaixo a lista dos possíveis privilégios:

ALL/ALL PRIVILEGES – Simboliza todos os privilégios abaixo;
ALTER – Permite alterar a estrutura de tabelas;
ALTER ROUTINE – Permite alterar e excluir stored procedures/functions;
CREATE – Permite criar base de dados e tabelas;
CREATE ROUTINE – Permite criar stored procedures/functions;
CREATE TEMPORARY TABLES – Permite a criação de tabelas temporárias em expressões SQL que utilizam esse recurso;
CREATE USER – Permite criar e gerenciar usuários;
CREATE VIEW – Permite criar visões;
DELETE – Permite excluir informações;
DROP – Permite excluir estruturas (bases e tabelas);
EVENT – Permite criar event schedulers;
EXECUTE – Permite executar stored procedures;
FILE – Permite ler e escrever arquivos no sistema;
GRANT – Permite cadastrar seus privilégios para outros usuários;
INDEX – Permite o gerenciamento de índices;
INSERT – Permite inserir informações em tabelas;
LOCK TABLES – Permite bloquear tabelas;
PROCESS – Permite visualizar e finalizar processos do MySQL;
RELOAD – Permite recarregar bases de dados;
REPLICATION CLIENT – Permite solicitar replicação;
REPLICATION SLAVE – Permite replicar suas informações;
SELECT – Permite consultas;
SHOW DATABASES – Permite visualizar todas as estruturas das bases existentes;
SHOW VIEW – Permite visualizar os códigos de criação de visões;
SHUTDOWN – Permite desligar o servidor MySQL;
SUPER – Permite configurar os dados do servidor MASTER (em caso de replicação);
TRIGGER – Permite criar e gerenciar triggers;
UPDATE – Permite alterar informações em tabelas;
USAGE – Permite utilizar comandos básicos.

Vamos criar uma usuária chamada amanda (sugiro a criação de um usuário específico para acesso remoto, uma das vantagens é a identificação nos arquivos de log) e ja definir seus privilégios, isso será feito através do comando GRANT, a sintaxe do mesmo é:

GRANT <privilégios> ON <base>.<tabela> TO '<usuario>'@'<dominio>' IDENTIFIED BY '<senha>'

Sendo que

*.* – Aplica-se a todas as bases!
<base>.* – Aplica-se a todas as tabelas da base determinada
<base>.<tabela> – Aplica-se a uma determinada tabela

Criando a usuária amanda e atribuindo seus privilégios:
$ mysql -u root -p -D mysql
mysql> GRANT SELECT,INSERT,DELETE,UPDATE ON test.* TO 'amanda'@'%'
IDENTIFIED BY 'senha da amanda';
Nota:  O uso de ' %' define que a usuária poderá se logar tanto localmente quanto remotamente.

Observação: O Comando GRANT cria um novo usuário e atribui privilégios a cada vez que é utilizado, se você estiver realizando alguns testes nesta parte, recomendo que ao terminar de um select na tabela user para verificar se não foi criada mais de uma entrada para o mesmo usuário com hosts diferentes, para revogar privilégios utilize o comando REVOKE

Para habilitar conexões remotas ao seu servidor MySQL vamos considerar o cenário do diagrama abaixo, o IP 200.220.4.113 é apenas para fim ilustrativo, substitua-o por seu IP externo! para descobrir seu IP externo visite o site  ifconfig.me ou o Ip Chicken.
Vamos começar com o mínimo de alterações e caso isso não seja o suficiente partiremos para outra etapa, assim restringimos as mudanças ao que for realmente necessário.

Primeiro o arquivo my.conf (o oposto do que fizemos no início deste tutorial) vamos comentar a linha skip-networking (caso essa linha não exista não é necessário cria-la) e alterar o bind-adress para 0.0.0.0, ao comentar a linha skip-networking estamos habilitando as conexões via tcp/ip, ja o bind-adress como 0.0.0.0 permite conexões de qualquer faixa de ip.
#skip-networking
bind-address        = 0.0.0.0
Se ao tentar um login remoto ocorrer o erro:
$ mysql -u amanda -p -h 200.220.4.113 -P 3306
ERROR 1042 (HY000): Can't get hostname for your address
Procure a linha abaixo no arquivo my.conf, caso exista certifique-se de que ela não está comentada com #, caso não exista, crie-a.
skip-name-resolve
Se depois disso você receber time-out
$ mysql -u amanda -p -h 200.220.4.113 -P 3306
Enter password:
ERROR 2003 (HY000): Can't connect to MySQL server on '200.220.4.113' (110)
Talvez seu firewall esteja bloqueando a conexão, se for este o caso adicione a seguinte regra ao firewall:
$ sudo ufw allow 3306/tcp
Para verificar se a regra foi adicionada corretamente
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
3306/tcp                   ALLOW       Anywhere
3306/tcp                   ALLOW       Anywhere (v6)
Se tudo estiver correto você conseguirá logar remotamente:
$ mysql -u yourusername -p -h 200.220.4.113 -P 3306 # Use seu IP externo!
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.

Copyright (c) 2000, 2013, Oracle and/or its affiliates. 
All rights reserved.

Oracle is a registered trademark of Oracle Corporation
and/or its affiliates.
Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear
the current input statement.

mysql>

É isto! 

Observação: Se ainda assim não conseguir conectar remotamente e você utilizar um roteador, será preciso redirecionar a porta do roteador para sua máquina, porém devido a imensa diversidade de modelos de roteadores não irei incluir isto neste tutorial, mas você encontrará informações sobre como fazer o "foward" de portas de diversos modelos no site Port Foward


Para remover a usuária amanda que foi criada apenas como teste:
$ mysql -u root -p -D mysql
mysql> DELETE FROM user WHERE user='amanda';
Para bloquear novamente o acesso no firewall mude a regra de allow para deny:
$ sudo ufw deny 3306/tcp

 

Interrompendo o inicio automático do servidor MySQL

Geralmente após instalado o servidor passa a ser iniciado como um serviço no boot do sistema, se você o utiliza apenas eventualmente quando está em produção e não como servidor permanente local, como medida de segurança adicional recomendo iniciar o servidor apenas quando você for trabalhar com o mesmo. O cancelamento do início automático pode ser feito de duas maneiras.

A Primeira é criando um arquivo override com a instrução "manual", a  vantagem deste metódo é que você não precisa alterar o arquivo de inicialização do MySQL, (caso queira voltar a inicializar o servidor automaticamente no boot basta remover o arquivo mysql.override.)

Criando o arquivo mysql.override
$ sudo touch /etc/init/mysql.override 
$ echo "manual" | sudo tee /etc/init/mysql.override
A outra opção é como root comentar a seguinte linha no arquivo /etc/init/myql.init
#start on runlevel [2345]
A partir dai para iniciar manualmente o servidor:
$ sudo initctl start mysql
Para interromper o servidor:
$ sudo initctl stop mysql 
Como alternativa também é possível iniciar ou parar o servidor através do comando service mysql <start /  stop>

Dúvidas? Deixe um comentário!

Trilha sonora deste post: Emma Hewitt - Colours (Jerome Isma-Ae Remix)

domingo, 16 de junho de 2013

Ruby: Verificando MD5 de arquivos

Postado por DoctorRu (Will)


Um pequeno  script que escrevi para verificar o MD5 de arquivos.

A primeira linha indica onde está o executável do ruby no seu sistema, se estiver usando windows mudar para o path usado, ex: c:\ruby\bin

Utilizei a biblioteca MD5 para calcular o hash do arquivo e depois realizar a comparação.

Para utilizar esse script ou você torna esse arquivo executável com: chmod +x md5check.rb e depois o executa com: ./md5check.rb <arquivo a ser verificado> <MD5 fornecido> ou chame-o da maneira tradicional com: ruby  md5check.rb <arquivo a ser verificado> <MD5 fornecido> o código é auto explicativo, mas qualquer dúvida é só deixar um comentário.

#!/usr/bin/env ruby
# encoding:UTF-8
#
# MD5 Simple checker
# by DoctorRu | http://rubydoit.blogspot.com | 2013-06-16
# 
# Usage: ruby md5check.rb <file name> <provided MD5> 
# or change the mode of this file to +x 
# and: ./md5check.rb <file name> <provided MD5>

require 'digest'

if ARGV[0] == nil || ARGV[0] == "--help" || ARGV[0] == "-h" 
  puts "Usage: md5check <file> <provided MD5>" 
else
  if File.exists?(ARGV[0])
    File_name  = ARGV[0]
    Md5_source = ARGV[1] || "nil : try md5check -h"
    Md5_sum = Digest::MD5.hexdigest(File.read(File_name))   
    puts "File\t=> #{Md5_sum}\nSource\t=> #{Md5_source}"
    puts "Compare\t=> #{Md5_sum == Md5_source ? 'MD5 passed!' : 'MD5 failed'}"
  else   
    puts "File not found"
  end
end
Exemplo de uso:
$ ./md5check.rb opera_12.15.1748_amd64.deb a7e6125c04d99562de643e6caf1781b9
File    => a7e6125c04d99562de643e6caf1781b9
Source  => a7e6125c04d99562de643e6caf1781b9
Compare => MD5 passed!

quarta-feira, 15 de maio de 2013

O editor de código mais espetacular do mundo!

Postado por DoctorRu (Will)

Não vou perder mais tempo do que escrever alguns curtos parágrafos sobre qual é o melhor editor de código, isso é como o fanatismo entre fotógrafos que usam Nikon e fotógrafos que usam Canon, quando o que realmente interessa é o olhar fotográfico e o resultado final, neste caso, que o código funcione!

Sugerir é aceitável, mas discutir qual o melhor editor de código é uma completa bobagem pois da mesma maneira que cada pessoa senta em uma cadeira na posição que considera mais confortável o mesmo se aplica a ferramenta se digita código.


No Linux comecei utilizando o Netbeans, ja no windows  o Aptana Studio estes foram os que melhor me adaptei entre as IDE's e editores que testei, quanto ao VIM e gVim (o primeiro é a versão console e o segundo a versão gráfica) apesar de prático para algumas coisas é um editor e não uma IDE, uma das suas maiores vantagens é estar disponível em toda instalação linux por padrão.


Uma outra alternativa é o Geany de interface agradável e leve mas com   suporte apenas razoável ao Rails (caso resolva testa-lo procure no google por "geany green line" você vai entender...), a maioria dos editores suporta plugins e scripts feitos por terceiros para adicionar conveniências para outras linguagens.

Para o Vim alguns plugins indispensáveis são o NerdTree, Snipmate e Surround, respectivamente: Adicionar lista de diretórios, auto completar instruções e fechamento automático de tags, em particular o Vim apesar de ter uma maior curva de aprendizagem é o predileto entre programadores, é vintage, é cult, e depois de umas duas semanas de uso constante você se adapta a infinidade de atalhos, vale a pena o esforço, confira alguns no Tuxfiles e também no Keyxl.

Existem diversas opções para edição de código, do Vim ao Dreamweaver, mas qual em uma quase infinita lista seria o melhor? Adivinhe... é aquele ao qual melhor você se adapta.

Vale lembrar que para escrever código bastam caneta e papel, afinal, código é poesia ou não?

Bom código a todos.

Trilha sonora deste post:  System of Down - Aerials

Entendendo exatamente Throw / Catch

Postado por DoctorRu (Will)

Um dos problemas com tutorais na web é que muitos são apenas copias traduzidas do manual sem nenhuma explicação pessoal do plagiador.

Se quem le não entendeu o exemplo, boa sorte na jornada, por isso resolvi explicar com mais detalhes o funcionamento do desvio throw / catch, eu mesmo demorei para entender o porque do throw estar localizado em alguns exemplos dentro do catch, agora explicando melhor:


A idéia de um throw aninhado dentro de um catch funciona assim:

Execute  o bloco de código abaixo até encontrar um throw, ao encontra-lo pare de executar o bloco de código e continue executando o que estiver na sequência.

O que dificulta o entendimento inicial de de throw / catch é que a tradução desses dois comandos equivale a "Jogue" / "Pegue" o que da a impressão de que o controle do código será transferido para o bloco catch quando o que realmente acontece é "um Jogue para fora de" / "Isto aqui" fazendo com que o controle saia do bloco catch.
# encoding:UTF-8
y = 0

catch(:prematuro) do

  while y < 10
    puts y  += 1
    throw :prematuro if y == 5
  end

  puts "Essa linha não será executada"

end

puts "O 'throw:prematuro' fez com que o bloco iniciado por catch fosse finalizado"
Equivale exatamente a:
y = 0
while y < 10
  puts y  += 1
  y = 10 if y == 5
end
throw / catch podem ser utilizados entre métodos diferentes, neste caso quando o throw for acionado ele voltará recursivamente até encontrar o catch, imagine que você está em uma trilha e para continuar você deve entrar em uma caverna para chegar do outro lado da trilha, então você vai descendo cada vez mais, passando por níveis mais profundos, ao acionar o throw você seria automaticamente teleportado para o lado de fora da caverna, como se ja a tivesse atravessado, mesmo que restassem mais níveis.
# encoding:UTF-8
def level_1
  puts "Entrando no level 1"
  catch(:caverna) do
    level_2
  end
  puts "throw! niveis 1-4! Saindo da caverna sem atingir o level 5"
end

def level_2
  puts "Entrando no level 2"
  level_3
end

def level_3
  puts "Entrando no level 3"
  level_4
end

def level_4
  puts "Entrando no level 4"
  throw :caverna
  level_5
end

def level_5
  puts "Este level não será atingido"
end

level_1
Produz:
Entrando no level 1
Entrando no level 2
Entrando no level 3
Entrando no level 4
throw! niveis 1-4! Saindo da caverna sem atingir o level 5
Este post foi escrito ao som de [OST] Ace Combat Zero - Zero