quinta-feira, 4 de fevereiro de 2016

Fusos horários brasileiros no Ruby on Rails

Estou fazendo um sistema onde o usuário pode adicionar uma data limite para a execução de algumas operações, após trabalhar um pouco em algumas telas e ter que fazer algumas conversões na data e hora para ser exibida corretamento no Bootstrap 3 Datepicker, me veio a preocupação em relação aos fusos horários brasileiros.

Inicialmente pensei em adotar o horário de Brasília e colocar observações nos locais onde as datas e hora seriam exibidas, pois inicialmente o sistema teria um uso maior nas regiões que utilizam este fuso horário, além disso tornaria a implementação um pouco mais fácil.

Depois pensei em como eu gostaria que o sistema se comportasse se fosse eu o usuário, aí não restou dúvida, mesmo sabendo que o público alvo se concentraria mais em uma região, o serviço ainda continuará na nuvem, podendo ser acessado de todo o território nacional.

O Brasil possui 27 Unidades Federativas, sendo que apenas 9 utilizam o horário de Brasília, desta forma optar por utilizar apenas este fuso horário, seria ignorar 18 UFs!

Existem diversos posts a respeito de como utilizar o fuso horário do usuário que fez a requisição, um é o It's About Time (Zones) do pessoal da thoughtbot, que descreve até a inclusão do campo do fuso horário na edição do perfil do usuário.

A classe do Rails que contem os fusos horários é a ActiveSupport::TimeZone, porém o único fuso horário brasileiro é o de Brasília e eu gostaria de colocar todos os fusos horários, são apenas 4, nas primeiras opções do select.

A biblioteca TZInfo, utilizada pelo ActiveSupport::TimeZone, apresenta os seguintes fusos para o Brasil:

br = TZInfo::Country.get('BR')
br.zone_names
=> ["America/Noronha",  "America/Belem",  "America/Fortaleza", "America/Recife",
"America/Araguaina",  "America/Maceio", "America/Bahia",  "America/Sao_Paulo",
"America/Campo_Grande", "America/Cuiaba",  "America/Santarem",  "America/Porto_Velho",
"America/Boa_Vista",  "America/Manaus",  "America/Eirunepe", "America/Rio_Branco"]

Para adicionar os novos fusos, criei o arquivo config/initializers/active_support/time_zone.rb com o seguinte conteúdo:

ActiveSupport::TimeZone::MAPPING['Fernando de Noronha'] = 'America/Noronha'
ActiveSupport::TimeZone::MAPPING['Amazônia'] = 'America/Manaus'
ActiveSupport::TimeZone::MAPPING['Acre'] = 'America/Rio_Branco'
ActiveSupport::TimeZone.instance_variable_set('@zones', nil)
ActiveSupport::TimeZone.instance_variable_set('@zones_map', nil)
module ActiveSupport
  class TimeZone
    def self.br_zones
      @br_zones ||= all.find_all { |z| z.name =~ /Brasilia|Noronha|Amazônia|Acre/ }
    end
  end
end

Fiz um mapeamento usando os nomes dos fusos horários que estão na Wikipédia, forcei as variávies @zones e @zones_map para nil, pois elas são cacheadas durante a criação do objeto que representa a classe ActiveSupport::TimeZone, desta forma quando  clientes da classe fazem uso dos métodos all e/ou zone_maps (as únicas formas de acessá-las sem metaprogramação), estas variáveis são recomputadas.

Por último adicionei o método br_zones, inspirado no método us_zones, presente na classe, o que facilita a criação do select:

<%= f.input :time_zone, priority: ActiveSupport::TimeZone.br_zones %>

terça-feira, 8 de setembro de 2015

Integração entre Rails e Iugu

Já faz algum tempo que comecei uma integração entre uma aplicação Rails e o iugu. Postei no grupo Ruby on Rails Brasil a respeito da abordagem que estou utilizando, tanto para compartilhar a ideia, quanto para obter um feedback para tentar deixar a coisa mais simples.

Neste meio tempo, um aspecto desta integração começou a me incomodar, então resolvi fazer este post para comentar sobre isto e também compartilhar partes do meu código a pedido de alguns usuários do post no face. Quem sabe agora eu recebo algum feedback!!! :-)

Meu modelo User estava com o seguinte código:

  after_create :create_iugu_customer
  after_update :update_iugu_customer, if: 'name_changed? or email_changed?'

  private

  def create_iugu_customer
    iugu_customer = Iugu::Customer.create({
      email: self.email,
      name:  self.name
    })
    self.update_column(:iugu_customer_id, iugu_customer.id)
  end

  def update_iugu_customer
    customer = Iugu::Customer.fetch(self.iugu_customer_id)
    customer.email = self.email
    customer.name  = self.name
    customer.save
  end


Pode ser apenas paranóia minha, mas esse é um tipo de código que me incomoda, pois vou precisar de um usuário para muitos testes do meu sistema, porém para a grande maioria deles não preciso de um Iugu::Customer. Ter meu teste conversando com uma API externa também me incomoda, para este último caso posso utilizar o VCR, porém imagine adicionar o VCR a diversos testes para utilizar a rede sendo que você não precisa do Iugu::Customer, incoerente não?

Pensando nisso googlei um pouco e li sobre algumas alternativas, tal como desligar callbacks durante a execução dos testes, criar um camada de serviço, etc. A mais coerente para mim era criar uma camada de serviço, porém analisando os requisitos da aplicação achei que uma complexidade desnecessária. Optei por criar o Iugu::Customer apenas quando necessário.

Minha feature ficou então da seguinte forma:

require 'rails_helper'

feature "Payment" do
  include ActiveJob::TestHelper
  let(:today) { Date.today }

  scenario "I should see a link to pay the service annuity", vcr: { cassette_name: 'iugu' } do
    # Given an event
    user = create(:user_confirmed)
    perform_enqueued_jobs do
      create_service(user)
      simulate_iugu_controller_webhook('invoice.created')
    end
    expect(page).to have_content('Você possui 30 dias para experimentar nosso sistema, aproveite!')
    expect(page).to have_content('Gostou do serviço? Contrate agora!')
    
    # When the user ask to contract the service
    click_link 'Contrate agora'

    # Then I can view my invoice with a payment link
    within '.box#invoices' do
      expect(page).to have_content('UUID')
      expect(page).to have_content('Anuidade serviço BLAH BLAH BLAH')
      expect(page).to have_content(I18n.l(today + 30.days))
      expect(page).to have_content('Pendente')
      expect(page).to have_content('R$ 999,99')
      expect(page).to have_xpath("//a[@href='https://iugu.com/invoices/uuid']")
    end
  end

  private

  def simulate_iugu_controller_webhook(event, data = {})
    data[:id]              ||= 'INVOICE_UUID'
    data[:status]          ||= 'pending'
    data[:subscription_id] ||= 'SUBSCRIPTION_UUID'

    Webhooks::Iugu::InvoiceCreationJob.perform_later(data)     and return if event == 'invoice.created'
    Webhooks::Iugu::InvoiceUpdateStatusJob.perform_later(data) and return if event == 'invoice.status_changed'

    raise "Iugu event not recognized: #{event}"
  end
end


No post do face falei que utilizei um request spec, porém posso simular o comportamento do controlador em um feature spec, como pode ser visto acima. Para gravar toda a interação com o VCR é necessário utilizar a opção "record: :new_episodes", completar o UUID retornado pelo iugu e ir executando os testes até ter todos os dados da interação. Além do próprio cassette você pode utilizar o painel de controle do iugu e o ngrok para conseguir mais detalhes da interação.

Observe no começo do cenário que utilizei o método perform_enqueued_jobs, pois após a criação do serviço eu executo um JOB para criação de uma Iugu::Subscription:

class Service < ActiveRecord::Base
  after_commit :schedule_subscription_creation, on: :create

  private

  def schedule_subscription_creation
    SubscriptionCreationJob.perform_later(self)
  end
end


O conteúdo deste JOB é o seguinte:

class SubscriptionCreationJob < ActiveJob::Base
  queue_as :default

  def perform(service)
    @user = service.owners.first
    @user.iugu_customer_id.blank? ? create_iugu_customer : update_iugu_customer
    iugu_subscription = Iugu::Subscription.create({
      plan_identifier: "basic_plan",
      customer_id: @user.iugu_customer_id,
      expires_at: 30.days.from_now,
      subitems: [{
        description: "Anuidade do serviço BLAH BLAH BLAH",
        price_cents: '999999',
        quantity: 1,
        recurrent: true,
      }],
      custom_variables: [{
        name: 'service_id',
        value: service.id
      }]
    })
    service.create_subscription(iugu_id: iugu_subscription.id, iugu_attributes: iugu_subscription.attributes)
  end

  private

  def create_iugu_customer
    iugu_customer = Iugu::Customer.create({
      email: @user.email,
      name:  @user.name
    })
    @user.update_column(:iugu_customer_id, iugu_customer.id)
  end

  def update_iugu_customer
    customer = Iugu::Customer.fetch(@user.iugu_customer_id)
    customer.email = @user.email
    customer.name  = @user.name
    customer.save
  end
end


Decidi criar a assinatura de forma assíncrona, pois não preciso dela imediatamente, além de garantir que uma possível falha de comunicação com o serviço externo não irá impedir o usuário de experimentar o serviço.

E olha quem mais encontramos aí: o código para criar/atualizar o Iugu::Customer. Com isso adiciono o VCR apenas aos testes que realmente precisam. Acredito que a parte de atualização do Iugu::Customer pode acabar voltando para o modelo User, sendo executada somente quando existir um iugu_customer_id, mas apenas a utilização do sistema dirá se isto será necessário.

Se tiver alguma dúvida e/ou sugestão deixa uma mensagem!

quarta-feira, 10 de junho de 2015

Filme: As Vantagens de Ser Invisível

Achei um ótimo filme, depois de algum tempo descobri que existia o livro, comprei.

A adaptação para o cinema ficou muito boa, mas pra manter o chavão e ser sincero: o livro é melhor que o filme.

Repetindo, a adaptação ficou muito boa, mas um detalhe em específico me deixou muito chateado.

Em um determinado momento, Charlie (protagonista), vai defender seu amigo Patrick, que está apanhando de uns 5 caras.

No filme, parece que Charlie adquire uma força sobrenatural e nocauteia um dos brutamontes, mas no livro ele sabe bater, aprendeu com o irmão. Bata nos olhos, garganta e joelhos. Acho que isso é kung fu, não?

Um ótimo filme sobre a adolescência, seria ainda melhor sem essa apelação para o fantástico.

quarta-feira, 27 de maio de 2015

From Heroku to Dokku

I really like Heroku, it's very convenient!

Convenience normally have a price and this start to hit me. I was paying $20 for SSL endpoint and more $9 for database. Almost $30 for an application that is being reestructured and not accepting new clients, so no money!

After some googling I find this http://donpottinger.net/blog/2014/11/17/bye-bye-heroku-hello-dokku.html and decided to give it a try. I decide for the $5 plan in DigitalOcean.

I don't have any problem in deploying my application without configuring DNS, but after that I have to do so, because I use subdomains in my app. It's also good to have a hostname, because after installing Dokku you have to finish configuring it accessing the public IP address or your hostname if you already configured your DNS. As described in "Step 2: Setting up Dokku" of https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-dokku-application. Without this your app port will change in each deploy, so you can't have a stable URL for you app.

DigitalOcean already offer dokku 0.3.18, the latest version now, so you don't have to update it as Pottinger point out.

I have problem while compiling my assets, but after configuring DATABASE_URL to the database URL that I created there everything worked fine.

After everything configured, it's like pushing to Heroku, very cool!

Are you thinking in give DigitalOcean a try? Using the following link you win $10: https://www.digitalocean.com/?refcode=55506009d157

quinta-feira, 8 de janeiro de 2015

jQuery UI Draggable / Resizable with constrain and CSS scale transformation

There are a bunch of questions and solutions to the problems between the interaction of these technologies, these are the better solutions that I found:
  1. http://stackoverflow.com/questions/10212683/jquery-drag-resize-with-css-transform-scale
  2. https://gungfoo.wordpress.com/2013/02/15/jquery-ui-resizabledraggable-with-transform-scale-set/
  3. http://stackoverflow.com/questions/17098464/jquery-ui-draggable-css-transform-causes-jumping
Although they make an improvement, they aren't totally accurate. What they basically do is a calculation of the right position / size that the object must have after the interaction.

You can experiment with the example below, drag the small square to right. Your mouse will be outside the parent div before you hit the edge.

And now, the same example, with the solution presented in [3].

Nice, now the small square moves with the mouse, but it go beyond the parent when dragging or resizing and this was the tricky part to solve. I spend a day trying to figure out how I could solve this, so I'm sharing my solution.

First let's solve the draggable problem. The "bug" (jQuery UI guys don't want to address it, so it's not a bug) occurs because inside jQuery UI it's use absolute event positions.

Think about the parent without the scale, it will be bigger, right? So it's size to jQuery UI is beyond the limit of the scaled down version. What we need to do is inform jQuery UI that our representation is smaller.

I tried in many ways not monkey patch jQuery UI, but these efforts were fruitless. I had to expose the "contaiment" var in the ui parameter passed to callbacks. With this little modification I could use the start and stop callbacks to make jQuery UI work with my scaled containment sizes.

var dragFix, startFix, stopFix;

window.myApp = {
  layout: {
    zoomScale: 1
  },
  draggable: {
    _uiHash: function() {
      return {
        helper: this.helper,
        position: this.position,
        originalPosition: this.originalPosition,
        offset: this.positionAbs,
        containment: this.containment
      };
    }
  }
};

$.ui.draggable.prototype._uiHash = myApp.draggable._uiHash;

startFix = function(event, ui) {
  ui.containment[2] *= myApp.layout.zoomScale;
  return ui.containment[3] *= myApp.layout.zoomScale;
};

stopFix = function(event, ui) {
  ui.containment[2] /= myApp.layout.zoomScale;
  return ui.containment[3] /= myApp.layout.zoomScale;
};

dragFix = function(event, ui) {
  var deltaX, deltaY;
  deltaX = ui.position.left - ui.originalPosition.left;
  deltaY = ui.position.top - ui.originalPosition.top;
  ui.position.left = ui.originalPosition.left + deltaX / myApp.layout.zoomScale;
  return ui.position.top = ui.originalPosition.top + deltaY / myApp.layout.zoomScale;
};

Nice and clean, don't you think? After solving this, I guess that making resizable works would be easy. The inner workings of this can't be very different, right? Wrong, dead wrong. What I think will be solved in 5 minutes, take the hole day.

The resizable code is very different. I expected to see the same algorithms to apply movement constraints and other operations. This way, I had to find a new way to inform jQuery UI about my constraints.

After a day tinkering with resizable code trying to find a solution that need minimal changes to jQuery UI, like with the draggable code, I was unable to find a solution that I liked.

First, I realized that I need to change the methods e, w, n and s in _change to get correct widths and heights according to my zoom scale. This was something that could be done in the "resize" callback, but in this case it's too late in the algorithm, the scaled position is needed by internal methods, before we get a chance to change it.

After this I thought that I had ended, but resizing an element that isn't in the position 0, 0 make it grow beyond the edge of the parent. Digging a bit more, I found that I need some way to change the "woset" and "hoset" calculation, but I don't find anyway to do this without monkey patching the entire method.

The final solution is this:

Maybe you are asking yourself why I'm monkey patching. This is because I'm use Rails and I want to have the benefits of the asset pipeline.

I'm not very proud of it, so I would love to know better ways to accomplish my final result in a simple manner. If you know any, please share!

sábado, 3 de janeiro de 2015

New kid on the S3 direct upload block

Sometime ago I saw the post [Small Bites] Direct Upload para S3: a Solução Definitiva! do Akita. Ow, fantastic! I was just playing with S3 Direct Uploads solutions that are described around the web and that could save me lots of time and give me a well polished solution.

I start playing with refile and how I could integrate it with my application. It don't take much time to became disappointed.

I already use paperclip in my application, it's very well integrated, meets my requirements and I'd like how it organize files, so adapt what I have to refile would be a pain, but it opened my head that S3 Direct Upload can be simpler, so I decide to experiment.

I'd like how s3_direct_upload interact with S3, keeping the filename. This way I decide to make a hybrid of s3_direct_upload and refile: s3-upnow has born.

The idea of the gem is to be backend agnostic. For now it works only with paperclip, so if it's your upload gem, give a try to s3-upnow and your feedback. I guess that support others upload gems is not difficult.

I know that it's not well polished, but it's already working for me and maybe can work for you. If you find scenarios that it's causing problems, please let me know!

Happy hacking!

terça-feira, 30 de dezembro de 2014

Metaprogramming Ruby

I'm reading Metaprogramming Ruby 2: Program Like the Ruby Pros. I started to read it, because I guess that metaprogramming could make pieces of my code simpler, but I discovered that my problems are about abstractions. I just need better abstractions, nevertheless the concepts exposed in the book are very good and made me feel excited.

The first time I read about the Ruby object model I feel very impressed. Ruby is the first language that I learned with two concepts very new to me: dynamic typing and pure object oriented. So, understand how all the pieces fit together and get comfortable with the notion that everything is object, including classes, take some time to click.

I learn best by doing and now I'm experiencing an opportunity to apply metaprogramming (that I expect to blog in a near future). By doing and trying to understand what I was doing I can say that the Ruby object model clicked in my head, but one aspect that still confuses me a bit, and IMO isn't explained with great details in this book, is about method lookup.

How Ruby goes from the receiver of the calling to the location in the hierarchy of ancestors? One source of confusion was this picture:


I perceveid the object model in a very organized form: for each class, you have a singleton class and it's superclass is the singleton class of the class superclass. After you get it, it's not that complicated, but what I didn't perceived, was that in the middle of all this you can have modules!

This way, I was struggling in how I could add class methods to an existing class and also override some of it's methods. For example, for the following code:

module OneModule
  def my_method
    puts "OneModule.my_method"
  end
end

class MyClass
  class << self
    include OneModule
  end
end

How can I tweak my_method behavior? The first difficult that I had was map this code to the diagram above, since I didn't understand where the code was living.

After reading and re-reading the first chapters of Perrotta book, and tinkering with irb, I understand that it was going to the singleton class of MyClass.

This code provide insightful output:

p MyClass.ancestors
p MyClass.singleton_class.ancestors
p MyClass.methods(false) == MyClass.singleton_class.methods(false)
====
[MyClass, Object, Kernel, BasicObject]
[#, OneModule, #, #, Class, Module, Object, Kernel, BasicObject]
true

When you define a class method, it's stored in the singleton class. So if I would like to change a class method,  I have to change the singleton class, but this also puzzled me: how can I add it without removing the actual method?

From the output it's easy to see the solution, but it take me a while to realize that it was possible. I guess that the module methods where inserted in the singleton class, but the module is put as an ancestor of the singleton class.
With this knowledge in mind you can write the following:

module OtherModule
  def my_method
    puts "OtherModule.my_method"
    super
  end
end

class MyClass
  class << self
    include OtherModule
  end
end

p MyClass.my_method
p MyClass.singleton_class.ancestors
====
OtherModule.my_method
OneModule.my_method
[#, OtherModule, OneModule, #, #, Class, Module, Object, Kernel, BasicObject]

You can also call "super" in "OtherModule" and Ruby will chain the calls correctly.

After all, I still can't describe how method lookup works, and luckily someone blogged about it: Ruby's method lookup path, Part 1.

The algorithm can be resumed to the following:
  1. Methods defined in the object’s singleton class (i.e. the object itself)
  2. Modules mixed into the singleton class in reverse order of inclusion
  3. Methods defined by the object’s class
  4. Modules included into the object’s class in reverse order of inclusion
  5. Methods defined by the object’s superclass.
Armed with this, I'm by far better prepared to experiment and answer questions when they pop out. So nice, so good!