![](https://habrastorage.org/getpro/habr/upload_files/d5d/cfc/a34/d5dcfca348bd447477b4f0550da98d40.png)
Разработчики приложений на Ruby on Rails однозначно знают и используют гемы - библиотеки, которые являются частью фреймворка RubyGems, механизма управления библиотеками или пакетами в Ruby. Однако мало кто из них прибегает к использованию плагинов.
В этой статье мы хотим рассказать вам:
Что такое плагины
Для чего их используют
Как их создавать
Программисты всегда готовы применять существующие решения для возникающих проблем, не тратя слишком много времени. Особенно, когда речь идёт о Ruby on Rails, где гибкость является нормой, и использование существующих решений для различных задач считается само собой разумеющимся. Благодаря повторному использованию кода программист может сэкономить время и усилия, не изобретая при этом велосипед.
Ни один язык программирования не идеален, и команда Ruby не может добавить всё, что пожелает каждый из разработчиков. Поэтому в Rails 1.0 появилась система плагинов, чтобы сделать Rails действительно гибким, позволяющим программистам делиться готовыми решениями с другими разработчиками. Плагин — отличный способ упаковать часто применяемые решения общих проблем и повторно использовать код.
Команда Rails рекомендует публиковать все популярные плагины в RubyGems. Первый шаг перед тем, как вы сможете создать плагин, — понимание, является ли ваш плагин специфичным только для приложения, над которым вы работаете, или его можно использовать в различных приложениях. Если подключаемый модуль, который вы создаёте, зависит от приложения, он будет рассматриваться как vendor specific plugin. Если ваш плагин можно применять в различных приложениях, он считается гемифицированным плагином (gem plugin).
В наших проектах мы неоднократно использовали регистрацию с помощью учётных записей социальных сетей, поэтому для дальнейших проектов мы решили разработать гем, где регистрация для каждой социальной сети (Вконтакте, Одноклассники, Google, Apple) является отдельным плагином.
![](https://habrastorage.org/getpro/habr/upload_files/38c/ff9/89b/38cff989b1fe09bee53de3786d5874bb.png)
Для начала мы описали модуль Plugins:
развернуть код
require 'oauth_client/errors'
module OauthClient
# Module in which plugins should be stored. Also contains logic
# for registering and loading plugins.
module Plugins
@plugins = {}
# If the registered plugin already exists, use it. Otherwise, require it
# and return it. This raises a LoadError if such a plugin doesn't exist
def self.load_plugin(name)
unless @plugins[name]
require "oauth_client/plugins/#{name}"
raise OuathException, "plugin #{name} did not register itself correctly" unless @plugins[name]
end
@plugins[name]
end
# Delegate call to the plugin in a way that works across Ruby versions.
def self.configure(plugin, uploader, **opts)
return unless plugin.respond_to?(:configure)
plugin.configure(uploader, **opts)
end
# Register the given plugin, so that it can be loaded
def self.register_plugin(name, mod)
@plugins[name] = mod
end
end
end
Данный модуль позволил загружать и конфигурировать плагины.
Далее рассмотрим реализацию самих плагинов на примере Вконтакте и Одноклассники.
Для настройки регистрации через Вконтакте мы описали метод register, который выполняет все необходимые операции, а затем зарегистрировали данный плагин для того, чтобы в дальнейшем мы смогли его загрузить и использовать в нашем приложении:
развернуть код
require 'faraday'
require 'oj'
require_relative '../errors'
module OauthClient
module Plugins
module Vkontakte
BASE_URL = 'https://api.vk.com/method/account.getProfileInfo'
VERSION = '5.131'
def self.register(access_token: nil)
request = Faraday.new(
url: BASE_URL,
params: {
access_token: access_token,
v: VERSION
},
headers: { 'Content-Type' => 'application/json' }
)
data = Oj.load(request.get.body, symbol_keys: true)
raise OuathException, data[:error][:error_msg] if data[:error].present?
data[:response]
end
end
register_plugin(:vkontakte, Vkontakte)
end
end
Для запроса на API Одноклассники нужны дополнительные опции, поэтому в данном модуле мы определили метод configure:
развернуть код
require 'faraday'
require 'oj'
require_relative '../errors'
module OauthClient
module Plugins
module Odnoklassniki
BASE_URL = 'https://api.ok.ru/fb.do'
def self.configure(uploader, **opts)
uploader.opts[:odnoklassniki] ||= {}
uploader.opts[:odnoklassniki].merge!(opts)
end
def self.register(access_token: nil)
request = Faraday.new(
url: BASE_URL,
params: {
application_key: OauthClient.opts[:odnoklassniki][:key],
method: 'users.getCurrentUser',
access_token: access_token
},
headers: { 'Content-Type' => 'application/json' }
)
data = Oj.load(request.get.body, symbol_keys: true)
raise OuathException, data[:error_msg] if data[:error_msg].present?
data
end
end
register_plugin(:odnoklassniki, Odnoklassniki)
end
end
И наконец, базовый модуль OauthClient выглядит следующим образом:
развернуть код
require 'oauth_client/plugins'
require 'oauth_client/version'
module OauthClient
@opts = {}
def self.plugin(plugin, **opts)
plugin = Plugins.load_plugin(plugin) if plugin.is_a?(Symbol)
Plugins.configure(plugin, self, **opts)
plugin
end
def self.opts
@opts
end
end
С помощью метода plugin после установки гема в конфигурации config/initializers/oauth_client.rb появляется возможность загрузить плагины, необходимые тому или иному приложению.
Пример конфигурации для гема в приложении:
require 'oauth_client'
OauthClient.plugin :vkontakte
OauthClient.plugin :odnoklassniki, { key: ENV['OK_KEY' ] }
Данная настройка позволила нам подгружать только необходимые плагины. Например, если в приложении требуется регистрация через Вконтакте и Одноклассники, то использование плагинов для регистрации через Google или Apple недоступно. Так как они не были загружены ранее, то при их вызове появляется следующая ошибка:
![](https://habrastorage.org/getpro/habr/upload_files/64a/04d/5fb/64a04d5fbcf10eded31c367fa76cf82a.png)
Плагины - это хорошее решение для кода, которое вам можно будет использовать в других пакетах или приложениях. Он расширяет функциональность уже существующего приложения и добавляет функциональность для создания нового приложения с нуля.
Ссылка на гит с исходным кодом.