Primeiros Passos Com Tower

O que é o Tower

Framework Web com Node.js que parece exatamente com Rails, mas em CoffeeScript.

Instalando NodeJS

sudo apt-get update
sudo apt-get install git-core curl build-essential openssl libssl-dev
git clone https://github.com/joyent/node.git && cd node
git checkout v0.5.10
./configure
make -j2
sudo make install
node --version

Instalando NPM

curl http://npmjs.org/install.sh | sudo sh
npm --version

Instalando CoffeeScript

sudo npm install -g coffee-script
coffee --version

Instalando Tower

sudo npm install tower -g

Criando sua primeira aplicação

tower new app
cd app
tower server #subindo a aplicação -> localhost:3000

Mais informações aqui


Dicas Git

Estava pensando em escrever um post sobre algumas dicas para o Git, mas quando fui fazer umas pesquisas acabei encontrando esse site, traduzido pela comunidade RailsBr, que é bem interessante.

Fizeram uma divisão bem bacana, assim ficou bem fácil para quem esta começando, principalmente pela tradução para a nossa língua.


RVM Manter Versão do Ruby e Gemset Sempre Que Entrar Na Pasta Do Projeto Rails Pelo Console

É sempre uma chatisse, para quem usar o RVM ter que escrever no console rvm use versao_do_ruby@gemset, mas nem todos sabem que existe um comando no próprio RVM para fazer isso de forma automatizada lol. Abaixo segue o comando:

rvm --create --rvmrc versao_do_ruby@nome_gem_set
Ex.: rvm --create --rvmrc 1.9.3@blog

Esse comando irá criar um arquivo .rvmrc, na pasta raiz da aplicação, setando a versão do Ruby e gemset.

Simples e prático lol.


Meu Ambiente De Desenvolvimento

RVM

Significa Ruby Versions Manager, ou um gerenciador de versões Ruby, mas o RVM não é só para gerenciar versões Ruby ele também gerencia um conjunto de gems específicas para cada projeto seu.

Tutorial de instalação aqui

Git

Git é um sistema de controle de versão distribuído com ênfase em velocidade. O Git foi inicialmente projetado e desenvolvido por Linus Torvalds para o desenvolvimento do kernel Linux.

Tutorial de instalação aqui

Ruby

É uma linguagem de programação interpretada multiparadigma, de tipagem dinâmica e forte, com gerenciamento de memória automático, originalmente planejada e desenvolvida no Japão em 1995, por Yukihiro “Matz” Matsumoto, para ser usada como linguagem de script. Matz queria uma linguagem de script que fosse mais poderosa do que Perl, e mais orientada a objetos do que Python. Ruby suporta programação funcional, orientada a objetos, imperativa e reflexiva. Foi inspirada principalmente por Python, Perl, Smalltalk, Eiffel, Ada e Lisp, sendo muito similar em vários aspectos a Python.

Tutorial de instalação aqui

Ruby on Rails

É um framework livre que promete aumentar velocidade e facilidade no desenvolvimento de sites orientados a banco de dados (database-driven web sites), uma vez que é possível criar aplicações com base em estruturas pré-definidas. Frequentemente referenciado como Rails ou RoR, o Ruby on Rails é um projeto de código aberto escrito na linguagem de programação Ruby. As aplicações criadas utilizando o framework Rails são desenvolvidas com base no padrão de projeto MVC (Model-View-Controller). Atualmente na versão 3.2.

Tutorial de instalação aqui

Ubuntu

É um sistema operacional baseado em Linux perfeito para notebooks, desktops e servidores. Ele contém todos os aplicativos que você precisa - um navegador web, programas de apresentação, edição de texto, planilha eletrônica, comunicador instantâneo e muito mais.

Encontrado aqui

Sublime Text

“Um editor de código fonte que trabalha com todas as linguagens possíveis e imagináveis, no qual você tem recursos para tudo, a qualquer momento, de todas as formas. Parece uma propaganda muito grande, mas o Sublime Text é realmente fantástico e possui recursos que irão ajudar muito a vida de programadores em geral.”

Encontrado aqui

Basicamente é isso pessoal lol.


Login Devise Com Facebook

Acabaram de me pedir para mudar um sistema para logar com facebook, aproveitei e fiz logo um post lol.

Já que o sistema usava devise lol mamão com açucar.

Adicione essas gems no arquivo gemfile.

1
2
gem "omniauth-facebook"
gem 'oa-oauth', :require => 'omniauth/oauth'

Agora vamos criar um controller para fazer o trabalho de login, crie um diretório users e logo em seguida um controller com nome omniauth_callbacks_controller dentro da pasta. Segue o código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def facebook
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      flash[:notice] = I18n.t "devise.sessions.signed_in", :kind => "Facebook"
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to root_url
    end
  end

  def passthru
    render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
  end

end

Vamos adicionar o método find_for_facebook_oauth dentro do model User.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
    data = access_token.extra.raw_info
    if user = User.where(:email => data.email).first
      user
    else # Create a user with a stub password. 
      User.create!(:email => data.email, :password => Devise.friendly_token[0,20], :role => 'user')
    end
  end

  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
        user.email = data["email"]
      end
    end
  end

Não esqueça de habilitar a opção :omniauthable do devise no model User.

Vamos colocar as rotas no arquivo routes.rb

1
2
3
4
devise_for :users, :controllers => {:omniauth_callbacks => "users/omniauth_callbacks"}
devise_scope :user do
  get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru'
end

Agora abra o arquivo devise.rb que esta em config/initializers e bem no final habilite a opção abaixo:

config.omniauth :facebook, 'APP_ID', 'APP_SECRET'

Pegando sua APP_ID e APP_SECRET

Vá ate esse endereço https://developers.facebook.com/apps e clique no menu aplicativos depois em criar novo aplicativo de um nome para ele e clique em continuar.

Selecione o aplicativo e clique em editar aplicativo, na opção App Domain coloque:

Ex.: dominio.com.br

Clique em Website e coloque o endereço da aplicação

Ex.: http://dominio.com.br/

Agora é so pegar a APP_ID e APP_SECRET e substituir, não esqueça das aspas.

Adicione o link para logar na view e pronto lol.

<%= link_to "Conectar com Facebook", user_omniauth_authorize_path(:facebook) %>

Moip, Rails E Retorno Automático

Peguei do site deles lol

"O que é o Moip?

O Moip é uma empresa de pagamentos online do IG e da Ideiasnet, que possibilita
o envio e recebimento de pagamentos na internet por meio de cartões de crédito,
débito e boleto."

Vamos lá, primeiro vamos criar uma conta para usar o modo de desenvolvimento do Moip aqui

Logamos no sistema e pegamos o token e a key para usarmos na app link

Agora vamo ver a gem do Moip no github

Seguindo as instruções do github, adicionamos a gem no arquivo gemfile, eu coloquei assim:

gem 'moip', '1.0.2', :git => 'git://github.com/moiplabs/moip-ruby.git'

Dê bundle install e em seguinda adicionei o seguinte código no arquivo environments/production.rb:

1
2
3
4
5
MoIP.setup do |config|
    config.uri = "https://desenvolvedor.moip.com.br/sandbox"
    config.token = "SEU_TOKEN"
    config.key = "SUA_KEY"
end

Não esqueça das aspas, agora vamos configurar nossa conta de desenvolvimento do Moip para fazer o retorno automático.

Depois de logado, ir ate o menu: Meus Dados - Preferências - Notificação das Transações

Habilite a opção logo abaixo do “Notificação de Alteração de Status de Pagamento”, em azul.

No campo abaixo de “* URL de notificação:” coloque sua url até o método que irá receber o retorno automático.

Ex.: http://domonio.com.br/payments/confirmation

Agora vá até o menu Ferramentas - API MoIP, e escolha um dos métodos de integração.

Voltamos para a aplicação e criaremos o controller e os métodos para fazer pagamento e o retorno automático.

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
# encoding: utf-8
class PaymentsController < ApplicationController
  skip_before_filter :verify_authencity_token, :only=>[:confirmation]

  def checkout # pega informaçoes do pagador, meio de pagamento e envia para o MOIP
    @pagador = { :nome => "Antonio Rogerio Medeiros da SIlva Filho",
                :login_moip => "argerim",
                :email => "argerim@gmail.com",
                :tel_cel => "(89)(89)9986-2058",
                :apelido => "Rogerio Medeiros",
                :identidade => "SEUCPF",
                :logradouro => "conjunto primavera casa 10 quadra d",
                :numero => "10",
                :complemento => "",
                :bairro => "Primavera",
                :cidade => "Teresina",
                :estado => "PI",
                :pais => "BRA",
                :cep => "64003-530",
                :tel_fixo => "(86)3126-2312" }

    @credit = { :valor => "500.00", :id_proprio => "armsfilho-gmail-com", :forma => "CartaoCredito",
                :instituicao => "AmericanExpress",:numero => "345678901234564",
                :expiracao => "08/11", :codigo_seguranca => "1234",
                :nome => "João Silva", :identidade => "134.277.017.00",
                :telefone => "(21)9208-0547", :data_nascimento => "25/10/1980",
                :parcelas => "2", :recebimento => "AVista",
                :pagador => @pagador, :razao => "Pagamento" }

    response = MoIP::Client.checkout(@credit)

    # redireciona usuario para confirmar pagamento
    redirect_to MoIP::Client.moip_page(response["Token"])
  end

  def confirmation
    if request.post?
      notificador = params #MoIP::Client.notification(params)
      if params[:status_pagamento] == "1" # 1 para pagamento confirmado
        @user = User.find_by_slug(params[:id_transacao])
        @user.update_attribute(:locked, false) #aqui eu dou permissão para o usuário logar
      end
      render :nothing => true
    end
  end

end

Coloquei o meu, pois assim fica mais fácil você configurar o seu lol.

Arquivo routes.rb:

1
2
3
4
resources :payments do
    get 'checkout', :on => :collection
    post 'confirmation', :on => :collection
end

Você pode verificar tudo que vem no retorno pelo log de produção, lembrando que só ira funcionar se estiver em um servidor web.

Qualquer dúvida só perguntar pelo twitter.


Rails - Redirecionando Para Uma Página Específica De Acordo Com A Permissão Do Usuário, Após O Login

Isso é algo bem simples de ser feito, apenas adicionando esses métodos dentro do ApplicationController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private
  
  def stored_location_for(resource_or_scope)
      nil
  end

  def after_sign_in_path_for(resource_or_scope)
    if resource_or_scope.role == 'admin'
      admin_url
    elsif resource_or_scope.role == 'user'
      users_url
    else
      root_url
    end
  end

O que ele faz é bem simples de acordo com a permissão do User ele vai para uma página específica, senão para index da aplicação.

Poderia ser feito também com case do Ruby lol.


Controller em Rails Com respond_to e respond_with

Com o Rails 3 veio uma excelente novidade que é o uso do respond_to com respond_with, que se eu não me engano essa ideia veio do Merb, onde acabou deixando o controller um pouco mais enxuto, e também trazendo mais perfomance eliminando blocos necessários.

Então ao gerar um scaffold o Rails monta um controller da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
class DocumentsController < ApplicationController
  # GET /documents
  # GET /documents.xml
  def index
    @documents = Document.all

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @documents }
    end
  end
end

Eu eliminei as outras actions, mas sabemos que exite a repetição do bloco respond_to em todas as outras actions.

Normalmente a index responde a vários formatos, mudando o nosso controller para trabalhar com respond_to e respond_with, podemos retirar o bloco de todas as nossas actions, abaixo um exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
class DocumentsController < ApplicationController
  respond_to :html, :js, :xml
  def index
    @documents = Document.all
  end

  def create
    @document = Document.new(params[:document])
    @document.slug = SlugGenerator.new(@document.name).slugify!
    flash[:notice] = 'Document was successfully created.' if @document.save
    respond_with(@document)
  end
end

Também existe esse forma de implementar a index:

1
2
3
4
5
6
7
8
class DocumentsController < ApplicationController

  def index
    @documents = Document.all
    respond_with(@documents, :to => [ :html, :xml, :json, :atom ])
  end

end

No exemplo que tem a action create temos respond_with(@document), onde a action ira redirecionar para a action show do objeto, se você quer que ele siga para outra action é so adicionar :location => url

1
2
3
4
5
6
def create
    @document = Document.new(params[:document])
    @document.slug = SlugGenerator.new(@document.name).slugify!
    flash[:notice] = 'Document was successfully created.' if @document.save
    respond_with(@document, location => documents_url )
end

É assim que mais ou menos fica um simples controller meu em Rails:

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
# encoding: utf-8
class ColorsController < AdminController

  respond_to :html

  def index
    @colors = Color.all
  end

  def show
    @color = Color.find_by_slug(params[:id])
  end

  def new
    @color = Color.new
  end

  def edit
    @color = Color.find_by_slug(params[:id])
  end

  def create
    @color = Color.new(params[:color])
    @color.slug = SlugGenerator.new(@color.name).slugify!
    flash[:notice] = 'Color was successfully created.' if @color.save
    respond_with(@color)
  end

  def update
    @color = Color.find_by_slug(params[:id])
    @color.slug = SlugGenerator.new(@color.name).slugify!
    flash[:notice] = 'Color was successfully updated.' if @color.update_attributes(params[:color])
    respond_with(@color)
  end

  def destroy
    flash[:notice] = 'Color was successfully deleted.' if Color.find_by_slug(params[:id]).destroy
    respond_with(@color, :location => colors_url)
  end

end

Simples e rápido, peguei um controller já pronto nesse último exemplo lol.


Tratando :dependent => :restrict No Rails

Recentemente me veio uma dúvida referênte ao :dependent do Rails, pois eu não queria que um objeto fosse deletado se estivesse associado a outro, então teria que usar assim :dependent => :restrict. Até aqui tudo bem, mas quando eu tentava deletar um objeto associado, sempre gerava uma exception e a página não ficava no layout padrão da app. Bem ainda tranquilo fui até o ApplicationController e adicionei o seguinte código:

1
2
3
4
5
6
7
8
class ApplicationController < ActionController::Base
  protect_from_forgery

  rescue_from ActiveRecord::DeleteRestrictionError do |exception|
      redirect_to root_url, :alert => exception.message
  end

end

Só que ao deletar um objeto sempre redirecionava para a home da aplicação, e não era isso exatamente que eu queria, tinha que ficar na página que estava deletando o objeto, pensei um pouco tentei passar o nome do controller mais ou menos assim:

1
2
3
4
5
6
7
8
9
10
class ApplicationController < ActionController::Base
  protect_from_forgery

  rescue_from ActiveRecord::DeleteRestrictionError do |exception|
      redirect_to controller_name_url, :alert => exception.message
      #ou
      redirect_to "#{controller_name}"_url, :alert => exception.message
  end

end

Sempre aparecia um erro.

Então me veio aquela velha luz, lol, o código acabou desse modo:

1
2
3
4
5
6
7
8
class ApplicationController < ActionController::Base
  protect_from_forgery

  rescue_from ActiveRecord::DeleteRestrictionError do |exception|
      redirect_to :back, :alert => exception.message
  end

end

Provavelmente exista uma outra forma de fazer, mas essa ficou bem simples, e resolveu lol.


Criando uma Classe e Fazendo um Require da Mesma

Resolvi escrever esse post devido a essa seguinte duvida no grupo rails_br:

"Eu criei um arquivo dentro da pasta /lib para manter os estados do Brasil
que vou usar no cadastro da minha app, mas quando chamei na minha via eu
recebo essa mensagem de erro:
"uninitialized constant ActionView::CompiledTemplates::STATES". Também 
já adicionei a pasta lib pra ser carregada pelo rails, mas mesmo assim,
não resolveu. O código que usei para adicionar a pasta /lib para o 
autoload_paths do rails:
config.autoload_paths << File.join(config.root, "/lib")
O código da minha constante: https://gist.github.com/1822459
O que esta faltando?"

Primeira coisa a fazer é criar uma classe dentro da pasta lib no root da aplicação. Eu coloquei o nome do arquivo de states.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
# encoding: utf-8
class States

  NAMES = [
      [ "AC", "Acre" ],
      [ "AL", "Alagoas" ],
      [ "AM", "Amazonas" ],
      [ "AP", "Amapá" ],
      [ "BA", "Bahia" ],
      [ "CE", "Ceará" ],
      [ "DF", "Distrito Federal" ],
      [ "ES", "Espírito Santo" ],
      [ "GO", "Goiás" ],
      [ "MA", "Maranhão" ],
      [ "MT", "Mato Grosso" ],
      [ "MS", "Mato Grosso do Sul" ],
      [ "MG", "Minas Gerais" ],
      [ "PA", "Pará" ],
      [ "PB", "Paraíba" ],
      [ "PR", "Paraná" ],
      [ "PE", "Pernambuco" ],
      [ "PI", "Piauí" ],
      [ "RJ", "Rio de Janeiro" ],
      [ "RN", "Rio Grande do Norte" ],
      [ "RO", "Rondônia" ],
      [ "RS", "Rio Grande do Sul" ],
      [ "RR", "Roraima" ],
      [ "SC", "Santa Catarina" ],
      [ "SE", "Sergipe" ],
      [ "SP", "São Paulo" ],
      [ "TO", "Tocantins" ]
  ]

end

Em seguida faço um require do arquivo dentro ApplicationController:

1
2
3
4
require 'states'
class ApplicationController < ActionController::Base
  protect_from_forgery
end

E por fim dentro da view:

1
<%= f.select :state, States::NAMES, { :prompt => "Selecione o Estado"} %>

Simples e Rápido lol.