вторник, 20 октября 2015 г.

Как сделать rebuild для ThinkingSphinx в resque-scheduler

Озаботился я переходом от delayed job + whenever на resque + rescue-scheduler.

Вот хорошее описание кейса на тостере:

И в целом на почитать:

Очень много танцев с бубном,  и вот мой cron остался только для запуска переиндексации сфинкса.


однако вот такой джоб раз в полчаса делает свою работу:

class ReindexThinkingSphinxJob < ActiveJob::Base
  queue_as :ts

  def perform(*args)
    config = ThinkingSphinx::Configuration.instance
    config.controller.index :verbose => true
  end
end

в resque-schedule.yml добавляем

ReindexThinkingSphinxJob:
  every:
    - '30m'
  description: "Reindex for thingin sphinx"
  queue: ts


и вуаля!

пятница, 9 октября 2015 г.

Запилил Server Side Events на Rails 4.0

Подробнее здесь.
Несколько косяков.

1. Нужен сервер с поддержкой SSE. В моем случае это Puma.
2. Если не включить config.cache_classes = true и config.eager_load = true, то работать не будет, будет вечное ожидание отработки контроллера вызываемого через events.
P.S. Эта проблема решается включением опции Just add config.allow_concurrency = true to your development.rb.
3. При включении опций, указанных выше, есть проблема с автоматической подгрузкой измененного кода. Нужно останавливать вебсервер и заново его запускать, что, конечно, замедляет разработку.

Мои эксперименты закончились вот таким небольшим контроллером:

class Api::EventsController < ApplicationController
 include ActionController::Live
 skip_before_filter :authenticate_account!, only: [:index]

def index
      response.headers["Content-Type"] = "text/event-stream"
   
      redis = Redis.new
      redis.psubscribe('tickets.*') do |on|
      on.pmessage do |pattern, event, data|
      response.stream.write "event: #{event}\n"
      response.stream.write "data: #{data}\n\n"
      end
      end

    rescue IOError
      logger.info "stream closed"
    ensure
      redis.quit
      response.stream.close
    end
end


И в модели ticket.rb я добавил такие хуки

after_create :notify_create
after_destroy :notify_destroy


def notify_destroy 
    $redis.publish('tickets.destroy', self.to_json)
end
def notify_create
    $redis.publish('tickets.create', self.to_json)
end

В Javascript (Coffeescript) я делаю примерно следующее:

@source = new EventSource("/api/events")
source.addEventListener 'tickets.create', (e) =>
      jQuery.gritter.add
        title: 'Новый тикет'
        text: "Добравлен тикет"

      console.log "pushed ticket"
      @tickets.push(new Ticket($.parseJSON(e.data)))

    source.addEventListener 'tickets.destroy', (e) =>
      data = $.parseJSON(e.data)
      @tickets.remove (item) => item for item in @tickets() when item.id is data.id

пятница, 25 сентября 2015 г.

Более простой способ генерить class: "active" для активного контроллера

Все равно у нас все RESTful,

так что нашел хорошим способ делать так (для HAML)

%li{class: (request.path.include?(incidents_path) && "active")}

выставит у
  • если путь с контроллером будет содержаться в URL, так можно делать и с субконтроллерами.
  • пятница, 8 мая 2015 г.

    Rails 4.1+ не нужен Timecop для тестиррования

    Теперь для тестирования начиная с версии 4.1 есть встроенный фукнционал Time.travel

    ActiveSupport::Testing::TimeHelpers#travel

    Time.travel 1.day
    Time.travel -1.day
    
    Time.travel 1.day do
      User.create.created_at # => 1 day from now
    end
    
    Time.travel_to Time.new(2004, 11, 24, 01, 04, 44)
    Time.travel_to Date.new(2004, 11, 24)
    
    Time.travel_to Time.new(2004, 11, 24, 01, 04, 44) do
      User.create.created_at # => 2004-11-24 01:04:44 -0500
    end