0

Мы поддерживаем несколько Rails-приложений, которые все создают аналогичную проблему, и у нас нет действительно хорошего решения: все эти приложения содержат модели, которые должны сделать API-вызов внешним службы в их жизненном цикле.Организация API-вызовов в обратных вызовах

Возможные случаи:

  • Пользователя подписался на рассылке-абонентской-лист, при успешном создании
  • Цен на предложение синхронизируется с внешней торговой системой после обновления
  • Продукта обновляются в Search-индекс после обновления

Что мы exprienced к НЕ быть хорошим решением: Добавление этих кал ls к обратным вызовам модели after_*. Поскольку это быстро ломает тесты, все фабрики теперь должны иметь дело с api-вызовами.

Я ищу хороший способ организовать эти API-вызовы. Как вы, ребята, это делаете?

Идеи мы придумали, которые я считал не настоящий идеал:

  • Перемещение этих обратных вызовов к контроллеру. Теперь они легко забываются при создании объекта
  • Истекает асинхронный рабочий для обработки api-call. Затем каждое - даже небольшое приложение - должно иметь накладные расходы на задержанную очередь заданий, например sidekiq.

ответ

2

Если вас беспокоит тестирование, вы можете put the callback methods into a separate class и издеваться над классом обратного вызова во время тестирования. Вот пример использования RSpec, учитывая следующие Foo и FooCallbacks классов:

class Foo < ActiveRecord::Base 
    after_save FooCallbacks 
end 

class FooCallbacks 
    def self.after_save 
    fail "Call to external API" 
    end 
end 

Вы можете написать и успешно запустить спецификации вроде этого:

describe Foo do 

    before do 
    allow(FooCallbacks).to receive(:after_save) 
    end 

    it "should not invoke real APIs" do 
    Foo.create 
    end 

end 
1

Это, как я теперь сделал это, после того, как советование :

В Foo:

class Foo < ActiveRecord::Base 
    before_save Foo::DataSync 
end 

Foo:DataSync выглядит следующим образом:

class Foo::DataSync 
    def self.before_save(foo) 
    ...do the API-Calls... 
    end 
end 

Теперь для тестирования в RSpec Я добавил это:

Для spec_helper.rb:

config.before(:each) do 
    Foo::DataSync.stub(:before_save) 
end 

Обратите внимание, что config.before(:suite) не будет работать, так как Foo:DataSync не загружается при этом время.

Теперь foo_spec.rb содержит только это:

describe Foo do 
    let(:foo) {create(:foo)} 

    it "will sync its data before every save" do 
    expect(Foo::DataSync).to receive(:before_save).with(foo) 

    foo.save 
    end 
end 

Foo::DataSync может быть проверена следующим образом:

describe Foo::DataSync do 
    let!(:foo) {create(:foo)} 

    before do 
    Foo::DataSync.unstub(:before_save) 
    end 

    after do 
    Foo::DataSync.stub(:before_save) 
    end 

    describe "#before_save" do 
    ...my examples... 
    end 
end 
Смежные вопросы