terça-feira, 8 de dezembro de 2009

Search engine in Ruby on Rails




Quem não gosta de facilidades no hora de navegar na internet. Uma dessas facilidades pode ser chamada de simple text-full search engine. Em resumo são aqueles campos que aceitam qualquer coisa do usuário e devolve uma lista de possíveis registros procurados. 
Uma vantagem é que se o filtro de busca costuma ser cheio de critérios é só indexar no campo full-text e está resolvido... resolvido para o programador e para o usuário que irá digitar o que sabe no campo (ou seja não existe campo não nulo neste filtro). 


Existem vários exemplos desse campo: Google tem um campo bem grande na sua página inicial; mercado livre; submarino... tem um monte desses sites com essa solução.
O problema na minha empresa não era tão diferente. A gente trabalha num projeto baseado em CRM (Rails and DB2) e os contatos inseridos no banco possuem várias informações, ou seja a tela de pesquisa de um contato específico é possível por várias informações (nome, data de nascimento, e-mail, endereco, cidade, etc...), todas essas informações juntas ou avulsas. Ou seja, se eu fosse fazer um filtro para isso precisaria de um monte de javascript, pois para cada tipo de informação seria apresentado um campo... para data de nascimento um campo data, para código do contato um campo para inserir o codigo e assim por diante. Depois ainda precisaria filtra na controller, na action qual é o tipo da pesquisa se é por cidade, por nome, por data de nasc, por codigo e etc. É um inferno!
O text-full search resolve tudo isso e se pensarmos um pouco ainda adiciona algumas vantagens, uma dela é que eu posso fazer um levantamento facilmente, por exemplo: eu preciso dos aniversariantes do mês ou os aniversariantes do mês que moram em são paulo ou entao os e-mails dos moradores do bairro do Bom Retiro.


É uma soluçao muito legal para os sistemas. Para quem quiser saber mais sobre a tecnologia que utilizamos: Xapian. Existem outras mais: ferret, solr... tem outras é que eu não estou lembrando agora mas se vocês colocarem no google vão achar outras mais. O único problema é que para cada tecnologia você vai ter algumas restrição ou algo que não te deixe contente. Por exemplo tem uma dessas soluções que funciona apenas para alguns bancos de dados, outro exemplo é não conseguir indexar os novos registros inseridos em tempo de execução, ou então não conseguir associar informações de outras tabelas ou não conseguir fazer busca com range (ex. os aniversariantes do dia 1/1/2009 a 1/3/3009).  
Vai de cada um a escolha, vai depender muito do ambiente que se encontram.
É isso... Se alguem tiver alguma dúvida sobre como implementar o xapian para os seus projetos por favor me mande um e-mail Altherlex Alves.
Abraço e até mais.

Noticias de São Paulo Hoje (8 dez 2009 às 8 am)

Fala ae rapazeada... faz tempo que eu nao posto nada. Hoje estou com o dia livre.
Vou postar algumas fotos da nossa querida São Paulo.


Essa é da frente da minha casa..


terça-feira, 6 de outubro de 2009

Rails: Rotas


Fala rapazeada... Hoje algumas notas sobre rotas:

1º- Diferença entre member e collection:

map.resources :notas, :member => { :baixar => :get }
map.resources :notas, :collection => { :baixar => :get }
A rota para collection será: "/notas/baixar". E para member será necessário informar um id, assim: "/notas/2/baixar"

2º - Herança:

Da mesma forma que é preciso informar na model quando uma tabela depende da outra, assim:

class Pessoa < ActiveRecord::Base;end class Telefone < ActiveRecord::Base; belongs_to Pessoa; end


É necessário fazer suas relações nas rotas, assim:

map.resources :pessoas do |pessoa|
pessoa.resources :telefones
end

Ficando assim:
---------------------------------------------------------------------------------------------------------------------------------------------
| Método | Rota | Chamada |
---------------------------------------------------------------------------------------------------------------------------------------------
| new_pessoa GET | /pessoas/new | {:action=>"new", :controller=>"pessoas"} |
| formatted_new_pessoa GET | /pessoas/new.:format | {:action=>"new", :controller=>"pessoas"} |
| edit_pessoa GET | /pessoas/:id/edit | {:action=>"edit", :controller=>"pessoas"} |
| formatted_edit_pessoa GET | /pessoas/:id/edit.:format | {:action=>"edit", :controller=>"pessoas"} |
| pessoa GET | /pessoas/:id | {:action=>"show", :controller=>"pessoas"} |
| formatted_pessoa GET | /pessoas/:id.:format | {:action=>"show", :controller=>"pessoas"} |
| pessoa_telefones GET | /pessoas/:pessoa_id/telefones | {:action=>"index", :controller=>"telefones"} |
| formatted_pessoa_telefones GET | /pessoas/:pessoa_id/telefones.:format | {:action=>"index", :controller=>"telefones"} |
| POST | /pessoas/:pessoa_id/telefones | {:action=>"create", :controller=>"telefones"} |
| POST | /pessoas/:pessoa_id/telefones.:format | {:action=>"create", :controller=>"telefones"} |
| new_pessoa_telefone GET | /pessoas/:pessoa_id/telefones/new | {:action=>"new", :controller=>"telefones"} |
| formatted_new_pessoa_telefone GET | /pessoas/:pessoa_id/telefones/new.:format | {:action=>"new", :controller=>"telefones"} |
| edit_pessoa_telefone GET | /pessoas/:pessoa_id/telefones/:id/edit | {:action=>"edit", :controller=>"telefones"} |
| formatted_edit_pessoa_telefone GET | /pessoas/:pessoa_id/telefones/:id/edit.:format | {:action=>"edit", :controller=>"telefones"} |
| pessoa_telefone GET | /pessoas/:pessoa_id/telefones/:id | {:action=>"show", :controller=>"telefones"} |
| formatted_pessoa_telefone GET | /pessoas/:pessoa_id/telefones/:id.:format | {:action=>"show", :controller=>"telefones"} |
| PUT | /pessoas/:pessoa_id/telefones/:id | {:action=>"update", :controller=>"telefones"} |
| PUT | /pessoas/:pessoa_id/telefones/:id.:format | {:action=>"update", :controller=>"telefones"} |
| DELETE| /pessoas/:pessoa_id/telefones/:id | {:action=>"destroy",:controller=>"telefones"} |
| DELETE| /pessoas/:pessoa_id/telefones/:id.:format | {:action=>"destroy",:controller=>"telefones"} |
---------------------------------------------------------------------------------------------------------------------------------------------

3º - Namespace

Nao sei pra que serve... mas tivemos a necessidade de usa-lo pois, numa mesma estrutura de aplicativo existiam dois projetos. Ou seja, para identificar quais controllers sao usadas em um projeto e quais sao usadas em outro, voce pode suar o namespace, assim:

map.namespace(:projeto_um) do |um|
# rotas do projeto um
um.resources :pessoas
end

Dessa forma todos as controllers que são do projeto um, ficam numa pasta dentro de controllers chamada projeto_um e assim para o projeto_dois, ou quantos namespace eu tiver. Isso é válido para toda a estrutura da aplicação ou seja para views será necessário ter uma pasta nomeada com o namespace (projeto_um) com as respectivas views e assim por diante.

Isso ficará da seguinte forma:
http://localhost/projeto_um/pessoas

Ou seja, para todas as rotas eu terei o namespace na frente.

E quando eu tiver uma unica controller válida para os dois projetos, que namespace colocar na rota?
Vamos imaginar que no projeto um eu tenho a controller telefones que pode ser usada no projeto dois também... você pode fazer da seguinte forma:
map.namespace(:projeto_um) do |um|
um.resources :telefones, :namespace => nil
end
map.namespace(:projeto_dois) do |dois|
um.resources :telefones, :namespace => nil
end

Assim a controller telefone será acessada de qualquer namespace: projeto_um ou projeto_dois.

Lembrando que a controller e as views de telefone deverão ser posta fora das pastas que englobam os arquivos especificos de cada projeto. Ou seja, a controller telefone ficará dentro do diretorio controller.

É isso... não tem muito segredo, caso pareça o contrário aqui tudo o que você pode aprender sobre rotas, dentro das magias e convenções de RUBY ON RAILS.

Fica assim entao, rapazeada. Duvidas, correcoes, reclamações e/ou sugestoes fiquem a vontade para informar.

Abraço.

quarta-feira, 15 de abril de 2009

Aliando: Rails + Ajax


Ok, vamos a mais um post... Hoje sobre como aliar todo o poder da aplicação web, neste caso rails, com o poder da metodologia Ajax, neste caso o framework prototype.

O que vamos fazer é criar um método e chamar e receber os dados via javascript. Ou em outras palavras, javascript com acesso ao banco de dados.


Existe hoje muitos frameworks javascrit que facilitam o trabalho na hora de fazer requisições ajax, por exemplo: jquery, motools e no nosso caso prototype.

Como o rails é mantido sobre a metodologia MVC, ou MVC2, ou arquitetura três camadas, iremos criar uma action na controller que será visualizada pela requisição javascript.


Vamos lá então... É bem simples:

Esta é a controller:

	
	class TestController < ApplicationController
  def me_chama
    render :text => "Hello, world"
  end
end


Ok, agora vamos invocar este método através do javascript...


<script>
  function chama(){
    url = '/test/me_chama'; 
    new Ajax.Request(url, {onComplete: function(transport){ alert(transport.responseText); } });
  }
</script>

E é isso... o método Request da classe Ajax do prototype irá chamar a url '/test/me_chama', que é a controller + action e que retornará a string 'Hello, world'.


Ok, agora imagina toda vez que eu chamar a action “chama” eu quero passar um parametro e desse paramtero fazer uma pesquisa no banco...

Vamos lá... a função javascript vai agora enviar um parametro para ser recebido lá na camda de controller e ser feito o select ao banco. Este parametro será enviado via post, extamente desta forma:

<script>

function chama(){

url = '/test/me_chama/?id_pessoa=1';

new Ajax.Request(url, {onComplete: function(transport){ alert(transport.responseText); } });

} </script>

O parametro enviado chama 'id_pessoa' e será pego na action assim: params[:id_pessoa]

A action será mais ou menos assim... Antes a model( ORM ) Pessoa (Person) para retornar os dados do banco) :


class Person < ActiveRecord::Base; end

class TestController < ApplicationController

  def me_chama
    nome_pessoa = Person.find( params[:id_pessoa] ).nme_pessoa rescue 'Nenhuma pessoa encontrada para esse código'
    render :text => nome_pessoa.to_s
    
    #-- Ou passando um objeto jason:
    #pessoa = Person.find( params[:id_pessoa] )
    # render :json => nome_pessoa.to_json
  end

end

E é isso...

Aqui alguns tipos de parametros do método render do rails, para quem quiser saber mais.

Qualquer dúvidas, reclamações, sugestões e/ou erros de português é só entrar em contato...Abraço e até mais!!!


quinta-feira, 29 de janeiro de 2009

Números Primos + MMC + MDC + Ruby



Segue abaixo um exemplo de implementação de gerador de Números Primos + MMC (Mínimo Múltiplo Comum) + MDC (Máximo Divisor Comum) em ruby. É um resultado de uma prova de lógica que um amigo meu teve que fazer em java.
Colaborações prestimosas de Cirillo Ferreira.


require 'Mathn'
class Numeric
def multiplos(ate = 500)
(1..ate).to_a.map{|v| self*v}
end
def divisores(ate = 500)
(1..ate).to_a.map{|v| v if (self%v == 0)}.compact
end
end

module Math
def self.mmc(*valor)
compara( valor.inject([]){|h, i| h << i.multiplos} ).first
end

def self.mdc(*valor)
compara( valor.inject([]){|h, i| h << i.divisores } ).last
end

def self.nmr_primos
numeros_primos = []
(2..501).each{|i| numeros_primos << (2..i).detect{|j| j%j ==0 && i%j==0} }
numeros_primos.uniq!
end

private
def self.compara(arr)
arr.inject(arr[0]){|ac, i| ac & i}
end
end

Math::mmc(3,5,8)
=> 120

Math::mmc(3,5,8,9)
=> 360




Os métodos mmc e mdc são métodos que aceitam parâmetros indeterminado graças a uma coisa, da linguagem ruby, chamada operador splat, que é aquele asterisco na assinatura do método. Tem a finalidade de compactar os parâmetros num única array.

Este programa é um pequeno incremento da classe Numeric. Onde é adicionado dois métodos necessários para a resolução dos métodos mmc e mdc que são: multiplos e divisores.
Após é adicionado no módulo Math (por isso a chamada inicial require 'Mathn'), como métodos de classe, o mmc e o mdc.
O método comparar é um método usado localmente (private) para retornar de um array de arrays os valores comuns.
obs.: O método gerar_nmr_primos não é usado. Foi criado apenas para ilustração e fertilização das mentes.

Mais informações sobre a linguagem acesse: O que é Ruby...

-Depois desse pragmatismo todo dá até para tomar um café com mais calma...

Abraço,
e até a próxima.