Arquivo

Textos com Etiquetas ‘Rails’

Validates password strength in Rails app

13, dezembro, 2011 Sem comentários

Hello guys,

In the last weekend I finished a rubygem to validate the password strength. It’s a very simple gem, the code are available at github

To install:

gem install password_strong

It’s very simple to use, just add verify_strong in the attribute.

Example:

class User < ActiveRecord::Base

  verify_strong :password

end

In the future I gonna work in client side validation. Feel free to contribute.

Categories: Rails, Ruby Tags: , , ,

Integrations tests and Devise Login

27, outubro, 2011 Sem comentários

Yesterday I started doing a new project using devise gem to manage login features. When I started to do integration tests using rspec, I found a problem: devise test helpers doesn’t work with rspec integration test.
So this is a quick solution to fix this.

require 'spec_helper'
include Warden::Test::Helpers

describe "UserDashboards" do

  before(:each) do
    @user = Factory.create(:user)
    login_as @user, :scope => :user
  end

  it "should access dashboard" do
    visit users_dashboard_path
    page.should have_content("dashboard")
  end
end

At top of spec file, after require ‘spec_helper’ include Warden::Test::Helpers. And in the before(:each) block I just used a warden helper to do login.

Rails 2.3.10 on App Engine

26, dezembro, 2010 Sem comentários

Durante esse feriado de natal, estive testando o suporte a JRuby no Google App Engine. Conseguir rodar tanto uma aplicação feita com Sinatra quanto uma feita em Rails 2.3.10. Infelizmente a gem google-appengine ainda não suporta o Rails 3, mas esse suporte já está sendo desenvolvido.

Então pesquisando no Github achei um gist mostrando como gerar uma aplicação com Rails 2.3.10 e DataMapper, infelizmente não funcionou como deveria. Mas ao analisar percebi que o problema era não está incluindo o DataMapper::Resource no model, então fiz um fork do gist e modifiquei, testei e agora tudo está funcionando. Para acessar o gist clique aqui e divirta-se.

Categories: Gae, Java, JRuby, Rails, Ruby Tags: , , , , ,

Otimizando o front-end – Parte 1: Testando

28, novembro, 2010 Sem comentários

Esse é o primeiro post de uma séria voltada para como melhorar o desempenho de seu site/sistema web.
Hoje em dia, trabalhar com desenvolvimento web envolve vários fatores. Um deles é o desempenho, desenvolver um sistema/site que tenha uma performance boa também envolve diversos aspectos.
Existem algumas extensões para o firefox capaz de testar o desempenho da sua camada de visão, são eles o yslow do Yahoo! e o Page Speed do Google. Ambos tem basicamente as mesmas funcionalidades, que no geral se resume a testar a performance da sua camada de visão e lhe dá dicas de como melhora-las.
Ele lhe avisa, por exemplo, quando você tem uma imagem grande e está reduzindo sua visualização no html ou css. Dentre outras coisas, tais como: habilitar a compressão GZIP, diminuir o tamanho dos cookies, habilitar o cache para determinadas áreas/arquivos.
Enfim, é uma extensão super simples de usar e que não pode faltar a um Desenvolvedor web.

De volta ao blog

6, novembro, 2010 Sem comentários

Olá pessoa, sei que o blog anda meio parado. Os últimos 3 meses foram de muita correria, fui promovido no trabalho, assumindo o cargo de gerente do setor de desenvolvimento, o que tomou grande parte do meu tempo.

Oxente Rails

Fazendo um resumo dos últimos meses, em agosto estive em natal, no OxenteRails. Um evento de muita qualidade, recomendo a todos, em 2011 estarei lá novamente. Agradecimento ao meu grande amigo Karlisson que ofereceu hospedagem.

Software Freedom Day 2010

Em Setembro, estive em Campina Grande (cidade maravilhosa que espero ter o prazer de conhecer melhor) para palestrar no Software Freedom Day 2010 sobre Ruby On Rails e Desenvolvimento Ágil. Em breve estarei postando os slides da palestra aqui. Infelizmente estava um pouco doente e não conseguir ficar até o final do evento (minha voz acabou no momento que terminei minha palestra). Espero está lá novamente em 2011.

Atualmente

Estou no momento mexendo um pouco com aplicativos de Web Mapping com Ruby On Rails, já havia mexido com Java e agora como tenho dedicado meu tempo somente a Rails, achei interessante começar a fuçar.

Para quem tem interesse, existe uma excelente Gem chamada Spatial_Adapter, que auxilia o ActiveRecord a tratar os dados geográficos. Atualmente os Bancos suportados são:
PostgreSQL (com sua extensão espacial Postgis)
e o MySQL.
E para quem quer utilizar o Google Maps para exibição dos mapas no seu aplicativo, também já existe uma Gem para isso, a google_maps.

Resumindo é isso, tentarei postar pelo menos mensalmente no blog.

Happy Hack ;-)

Desenvolvimento com Rails, mongoid, rspec e cucumber

12, agosto, 2010 1 comentário

Nesse rápido post irei demonstrar como iniciar o desenvolvimento de uma aplicação com o Rails 2.3.8, utilizando como banco de dados NoSql o Mongodb.
Para conexão com o banco, utilizaremos a gem Mongoid. Também iremos configurar para testes o Rspec e o Cucumber. Considerando a parti daqui que você tem todas as gems citadas anteriormente instaladas no seu ambiente.
Primeiro começaremos criando uma aplicação Rails, nada de novo aqui.

rails app_teste

Com isso iremos gerar toda a estrutura da aplicação. Agora vamos configurar as gems utilizadas, em ‘config/enviroment.rb’, adicionaremos dentro do bloco ‘Rails::Initializer.run’ a gem do mongoid:

Rails::Initializer.run do |config|
  config.gem 'mongoid'
  config.time_zone = 'UTC'
end

Com a gem do Mongoid, não precisaremos mais do ActiveRecord, para remover de sua aplicação basta adicionar dentro do mesmo bloco que você configurou o a gem, a seguinte linha ‘config.frameworks -= [:active_record]‘. Deixando meu enviroment.rb assim:

Rails::Initializer.run do |config|
  config.frameworks -= [:active_record]
  config.gem 'mongoid'
  config.time_zone = 'UTC'
end

Quando utilizavamos o ActiveRecord, por padrão ele procurava um arquivo YAML chamado database.yml no qual continha as informações sobre o meu banco. No caso do mongoid, podemos continuar com esse mesmo arquivo, ou criar outro (no meu caso eu prefiro criar um chamado mongoid.yml).
Abaixo segue o meu arquivo yml:

base: &base
  adapter: mongodb
  # em tempo de execucao vamos adicionar o "-#{Rails.env}" ao nomo do banco
  database: "feedse"
# Se estiver rodando o mongodb em outro host,
#vc deveria autenticar-se
  #host: host.mongodb.com
  #username: your-username
  #password: your-password

# use as proximas linhas para colocar algo especifico a cada ambiente
development:
  <<: *base

test:
  <<: *base

production:
  <<: *base

Feito isso, agora precisamos que nossa aplicação leia esse arquivo e configure nossa conexão com o banco. Para isso, criaremos um arquivo chamado ‘mongo.rb’ (ou qualquer outro nome que você queira) dentro do diretório config/initializers.
mongo.rb

require 'yaml'

mongo_config = YAML::load(File.read(File.join(Rails.root, 'config/mongoid.yml')))[Rails.env]

Mongoid.configure do |config|
  config.from_hash(mongo_config)
end

Com isso, já temos tudo pronto em relação ao nosso banco.

Criaremos então, um model chamado ‘Content’. Lembrando que como não utilizamos mais o ActiveRecord, nossa classe não deverá herdar ActiveRecord::Base.

Abaixo segue a implementação da nossa classe:

class Content
  include Mongoid::Document
  field :title, :type => String

  validates_presence_of :title
  validates_uniqueness_of :title
end

Para que nossa classe seja persistida em nossa banco, precisamos incluir o include Mongoid::Document. Precisamos também definir os campos que ele vai ter, no nosso caso somente o campo ‘title’. A definição básica dos campos segue a seguinte estrutura ‘field , :type => ‘. Para mais informações consulte a documentação do mongoid.

Utilizando o RSpec

Vamos gerar a estrutura do rspec, como faríamos em qualquer outro projeto Rails.

script/generate rspec

Logo após gerar a estrutura, abra o arquivo spec_helper.rb dentro do diretório spec recém gerado, e dentro do bloco Spec::Runner.configure comente as seguinte linhas:

  config.use_transactional_fixtures = true
  config.use_instantiated_fixtures  = false
  config.fixture_path = RAILS_ROOT + '/spec/fixtures/'

Um dos problemas que enfrentei logo quando comecei a mexer com Rspec junto com MongoDb, foi que o rpspec não limpa o banco de testes após executar os mesmos. Logo isso deverá ser feito na mão, para isso adicionaremos dentro do bloco Spec::Runner.configure em o seguinte código:

  config.after(:each) do
    Mongoid.database.collections.each do |collection|
      unless collection.name =~ /^system\./
        collection.remove
      end
    end
  end

Deixando o nosso spec_helper.rb assim:

ENV["RAILS_ENV"] ||= 'test'
require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))
require 'spec/autorun'
require 'spec/rails'

# in ./support/ and its subdirectories.
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}

Spec::Runner.configure do |config|

  #config.use_transactional_fixtures = true
  #config.use_instantiated_fixtures  = false
  #config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
  #clean database mongodb after tests
  config.after(:each) do
    Mongoid.database.collections.each do |collection|
      unless collection.name =~ /^system\./
        collection.remove
      end
    end
  end

end

Nesse caso o Rspec irá limpar o banco depois de cada teste ‘each’, mas você pode efetuar a limpeza somente depois de todos os testes terem rodado, nesse caso ao invés de ‘:each’ como parâmetro, utilizaremos ‘:suite’, e caso você queira executar alguma coisa antes dos testes, utilize o ‘config.before’, que funciona exatamente da mesma maneira do ‘config.after’, com a diferença de ser executado antes(before) dos testes.

Obs: Se você está utilizando também o cucumber e está com problemas em relação a limpeza do banco após os testes, a solução é simples.
Crie o arquivo ‘clean_mongo.rb’ (ou qualquer outro nome) dentro de features/support e adicione nele o código abaixo:

After do |scenario|
  Mongoid.database.collections.each do |collection|
    unless collection.name =~ /^system\./
      collection.remove
    end
  end
end

E com isso temos nossos testes funcionando com o mongodb.

Pesquisa avançada com MongoMapper, simulando um “like %”

3, agosto, 2010 Sem comentários

Esse post é uma “continuação” do anterior, estarei demonstrando como fazer uma query no “like %” no MongoDb, utilizando a gem MongoMapper

Como no post anterior, eu tenho o model “Person”:

class Person
  include MongoMapper::Document
  key :name, String
  key :middle_initial, String
end

E eu preciso encontrar todos os registros (no caso do Mongodb, documentos) que contenham o nome “Silva” em ‘name’, podendo ter vários Silva’s, como: “João da Silva”, “Maria Silva” e etc…

A solução, mais uma vez, é simples:

Person.all("$where" => "function() { return this.name.match(/"Silva"/i)"})

Pesquisa avançada com Mongoid, simulando um “like %”

1, agosto, 2010 Sem comentários

Comecei semana passada a utilizar o Mongodb (utilizando a biblioteca mongoid) em um novo projeto que estou desenvolvendo. Embora a documentação do Mongoid seja excelente, tive problemas para utilizar uma query com o ‘like %%’ de pesquisa como eu utilizava em bancos de dados relacionais.
A solução que eu encontrei foi utilizar uma Regex no parâmetro de busca.
Imagine que eu tenho um model chamado Person, como o abaixo:

class Person
  include Mongoid::Document
  field :name
  field :middle_initial
end

E eu preciso encontrar todos os registros (no caso do Mongodb, documentos) que contenham o nome “Silva” em ‘name’, podendo ter vários Silva’s, como: “João da Silva”, “Maria Silva” e etc…

A solução é simples:

Person.find(:all, :conditions => {:name => Regexp.new("Silva")}).entries

Então será retornado um array contendo todos os documentos com o termo “Silva” no nome.

Categories: Mongodb, NoSql, Rails, Ruby Tags: , , , ,

Utilizando o is_paranoid

13, junho, 2010 2 comentários

O is_paranoid é uma gem que faz com que os registros do banco não sejam apagados através do método destroy. Ao chamar o método destroy nosso objeto é apenas marcado como apagado e pode ser restaurado posteriormente, bem como listado através de método fornecidos pelo is_paranoid.
Sua utilização é bem simples, primeiro instale a gem:

gem install is_paranoid

Para que funcione em sua aplicação Rails, adicione no enviroment.rb , dentro do bloco de inicialização:

config.gem "is_paranoid"

Deixando mais ou menos assim:

Rails::Initializer.run do |config|
  # ...
  config.gem "is_paranoid"
end

Agora, nos models que vão utilizar dos recursos do is_paranoid, adicione logo após a declaração da classe ‘is_paranoid’

Exemplo:

class Student < ActiveRecord::Base
  is_paranoid
end

E para finalizar, crie uma migrate que adicione na tabela que vai utilizar o is_paranoid, o campo ‘deleted_at’, do tipo ‘timestamp’.

Exemplo:

class AddIsparanoidInStudent < ActiveRecord::Migration
  def self.up
    add_column :students, :deleted_at, :timestamp
  end

  def self.down
    remove_column :students, :deleted_at
  end
end

Pronto! Se quiser saber mais sobre o is_paranoid, consulte a documentação oficial no site do projeto.

Categories: Dicas, Rails, Ruby Tags: , ,

Remember password com restful_authentication

10, abril, 2010 2 comentários

O restful_authentication é um plugin de autenticação para aplicativos ruby on rails, com excelentes recursos, super fácil de configurar. Enfim, não vou falar muito sobre ele, pois não é o propósito desse tutorial. Irei assumir que você já tem o restful_authentication funcionando e quer apenas adicionar a funcionalidade de enviar um código de reset password via email para o usuário que esqueceu sua senha. Ao acessar o link com esse código o sistema irá exibir uma tela de troca de senha, lembrando que esse código deverá ser único e poderá ser usado somente uma vez. Então vamos lá:

Primeiro iremos gerar uma migration que adiciona na tabela o usuário a coluna ‘reset_password_code’.

script/generate migration reset_password_code

Agora editarei a migration gerada, deixando da seguinte forma:

class ResetPasswordCode < ActiveRecord::Migration
  def self.up
    add_column :users, :reset_password_code, :string
  end

  def self.down
    remove_column :users, :reset_password_code
  end
end

em seguida, ‘rake db:migration’ e estaremos pronto para começar!

Na classe UsersController irei criar um método protected que irá gerar um código para ser enviado ao usuário.

protected
  def random_code( len = 40 )
    chars = (("a".."z").to_a + ("1".."9").to_a )- %w(i o 0 1 l 0)
    newpass = Array.new(len, '').collect{chars[rand(chars.size)]}.join
  end

Agora criarei o método que chamará a view com o campo para o usuário colocar seu email:

  def change_reset_password
  end

Agora criarei a view que receberá o endereço de email do usuário e chamará o método “reset_password” passando o email:

<p>
    <%= form_tag (:controller => 'users', :action => 'reset_password' ) %>

    <p>
        <%= label_tag 'Email' %>
        <br/>
        <%= text_field_tag (:email) %>
    </p>
    <p>
        <%= submit_tag 'Enviar' %>
    </p>
    <%= flash[:alert] %>
</p>

Já método reset_password, irá receber o email, procurar o usuário com esse email, gerar o código de reset password, e chamar o UserMailer para enviar o email com o código.

  def reset_password
    user = User.find_by_email(params[:email])
    unless user.nil?
      user.reset_password_code = random_code
      if user.save!
        UserMailer.deliver_new_password(user)
        flash[:done] = "Verifique seu email para trocar a senha"
        redirect_to ('/')
      else
        flash[:error] = "Erro ao efetuar trocar de senha"
        render :action => 'change_reset_password'
      end
    else
      flash[:error]  = "Email Inválido"
      render :action => 'change_reset_password'
    end
  end

Vejam que estou chamando “UserMailer.deliver_new_password(user)” e passando o usuário como parâmetro. Na classe ‘UserMailer’ devo criar o método ‘new_password’ que será usado para enviar o email.
Meu método new_password deverá ficar assim:

  def new_password(user)
    setup_email(user)
    @subject    += 'Mudança de senha'
    @body[:url]  = "#{$SERVER_CONTENT_BASE}/password/#{user.reset_password_code}"
  end

Agora criarei a view para esse email, dentro de ‘app/views/user_mailer’ com o nome de ‘new_password.html.erb’

Olá <%=h @user.login %> alguém solicitou a troca de senha para essa conta.
Se deseja realmente trocar sua senha, clique no link abaixo:
<%=h @url %>

Agora de volta ao UsersController, criarei o método que recebe o reset_code e se ele estiver correto será jogado em um campo hidden na view de troca de senha.

  def code_password_reset
    user = User.find_by_reset_password_code(params[:reset_code])
    if user.nil?
      flash[:error]  = "Código inválido"
      redirect_to ('/')
    else
      @reset_code = params[:reset_code]
      render :action => "new_password"
    end
  end

Criarei a view de troca de senha, chamada ‘new_password’

<p>
    <%= form_tag (:controller => 'users', :action => 'reset_password_update', :method => 'put' ) %>
    <p>
        <%= label_tag 'Nova Senha' %>
        <br/>
        <%= password_field_tag (:password) %>
    </p>
    <p>
        <%= label_tag 'Confirmação' %>
        <br/>
        <%= password_field_tag (:password_confirmation) %>
    </p>
    <%= hidden_field_tag(:reset_code, @reset_code) %>
    <p>
        <%= submit_tag 'Enviar' %>
    </p>
	<%= flash[:alert]%>
</p>

E agora o método que de fato executa a troca de senha:

  def reset_password_update
    @user = User.find_by_reset_password_code(params[:reset_code]) unless params[:reset_code].blank?
    if ((params[:password] == params[:password_confirmation]) && !params[:password_confirmation].blank?)
       @user.password_confirmation = params[:password_confirmation]
       @user.password = params[:password]
       @user.reset_password_code = nil
      if @user.save!
        flash[:done] = "Senha atualizada com sucesso!"
        redirect_to ("/")
      else
        flash[:alert] = "Falha ao atualizar senha."
        render :action => 'new_password'
      end
    else
      flash[:alert] = "Senhas diferentes!"
      render :action => 'new_password'
   end
  end

Para finalizar iremos configurar as rotas;

  map.resources :users, :collection => { :change_reset_password => :get,
                                         :new_password => :get, :reset_password_update => :post,
                                         :code_password_reset => :get, :reset_password => :get}
  map.connect 'password/:reset_code', :controller => 'users', :action => 'code_password_reset'

E assim chegamos ao fim desse tutorial.