class ApplicationPush < ActionPush::Base
  default :ios do |ios|
    ios.thread_id = 'fuck'
    ios.badge = 10
  end
end
class UserPush < ApplicationPush
  default :ios do |ios|
    ios.alert do |a|
      a.launch_image = 'user.png'
    end
  end

  def welcome
    # envelope#title and #body set corresponding
    # attributes for all registered providers like ios and android 
    envelope.title = 'hello'
    envelope.body = 'world'
    envelope.payload = { user_id: 1 }

    envelope.for(:ios) do |ios|
      ios.thread_id = 123     
    end

    # push method sets #scheduled = true to the message,
    # so this pushes will be delivered when you call a 
    # class method: `UserPush.welcome`
    push :ios, token: 'foo'
    push :android, token: 'bar'
  end


  def buy
    push :ios, token: 'foo' do |ios|
      # translations are available under the key:
      # en.user_push.buy.title
      #
      # You can set I18n scope by redefining i18n_scope method:
      #
      # def i18n_scope
      #   "self.class.to_s.underscore}.#{action_name}"
      # end
      ios.title = t('.title')

      # you can redefine scheduling in a block
      ios.scheduled = false
    end

    push :android do |android|
      android.token = 'foo' 
      android.title = t('.title')
    end
  end
end

Using with Sidekiq

# enable delay extension at `config/initializers/sidekiq.rb`
Sidekiq::Extensions.enable_delay!

@user = User.last
UserPush.delay_for(4.seconds).welcome(@user.id)

Configuration

gorush = ActionPush::Delivery::Gorush.new(
  url: 'http://localhost:8088/api/push', 
  topic: 'com.app.id',
  logger: STDOUT
)

ActionPush::Base.register_delivery_method :ios, ->(push) do 
   gorush.send_to_apple(push)
end

Testing

# spec/support/action_push.rb

ActionPush::Base.register_delivery_method :ios, ActionPush::Delivery::Memory

RSpec.configure do |config|
  config.before(:each) do
    ActionPush::Delivery::Memory.clear
  end
end
# app/models/user.rb

class User < ApplicationRecord
  def confirm
    update!(confirmed_at: Time.current)
    UserPush.welcome(id)
  end
end
# app/pushes/user_push.rb

class UserPush < ApplicationPush
  def welcome(id)
    user = User.find(id)

    envelope.title = 'Welcome push'
    envelope.body = 'Glad to see you'

    push :ios, token: user.ios_push_token
  end
end
# spec/models/user_spec.rb

RSpec.describe User do
  let(:user) do
    create :user 
  end

  it 'sends a push' do
    expect { user.confirm }.to change { ActionPush::Delivery::Memory.size }.by(1)
    expect(ActionPush::Delivery::Memory.last).to have_attributes(title: 'Welcome push', body: 'Glad to see you', token: user.ios_push_token) 
  end
end 

Interceptor

# config/initializers/action_push.rb

ActionPush::Base.register_interceptor = ->(instance, provider, _push, &block) do
  Logger.info <<~DOC
    Sending a push "#{instance.class}.#{instance.action} to #{provider}"
  DOC 

  block.call
end

Реализация провайдера

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

В этом примере провайдером будет выступать nchan

class WebsocketMessage < ActionPush::Provider::Base
  attr_accessor :chanel, :payload
end
class ApplicationPush < ActionPush::Base
  register_default :socket, WebsocketMessage.new
end
class FollowRequestPush < ApplicationPush
  def notify(user_id)
    user = User.find(user_id)
    push :socket, chanel: "pub/#{user.id}", payload: { title: t('.title') }
  end
end
# config/initializers/action_push

ApplicationPush.register_delivery_method :socket, ->(push) do 
  `curl http://nchan:8080/#{push.chanel} -X POST --data='#{push.payload.to_json}'`
end

Теперь вы можете слать уведомления прямо в браузер пользователя:

FollowRequestPush.notify(1)