при роботі з будь-яким додатком Rails, що не є "hello-world", неминуче потрібні невеликі AJAX-допоміжники для спілкування з сервером, щоб виконувати логіку на стороні клієнта. я не маю на увазі API як такий, а радше адхок утиліти, такі як ці:
markdown.change(function(){
generate_html_on_the_server( markdown.val(), function(html){
preview.html(html);
});
});
або
reservation.change(function(){
check_availibity_on_the_server( reservation.val(), function(data){
if(!data['available']){
alert('Цей час недоступний - виберіть інший!');
};
})
});
і т.д.
Ці типи функцій не є частиною серверно-серверного публічного API, це просто співпрацюючі JS/бекенд-ендпоінти, які потрібні для роботи відображення.
Більшість додатків Rails накопичують багато таких функцій, і виникає питання:
“Куди їх помістити?”
У більшості команд буде три або чотири розробники, які називають та організовують ці функції по-різному, забезпечуючи, щоб кодова база перетворилася на безладну макаронинну суміш в найкоротші терміни.
@dojo4 ми абстрагували це за допомогою невеликого шаблону проектування RPC: спочатку ми маємо невеликий DSL контролера, який включений до нашого ApplicationController, що дозволяє декларативні визначення допоміжників JS 'rpc' на основі кожного контролера.
class ApplicationController < ActionController::Base
include(RPC)
end
ознайомтесь з реалізацією тут: https://gist.github.com/ahoward/7320900
простою англійською мовою цей dsl просто визначив одну дію на контролері, яка мультиплексує, який метод використовувати на основі параметрів, і легкий спосіб визначити їх. він очікує, що всі дії rpc повернуть хеш і повернуть json.
його реалізація зводиться до
def rpc
which = params['method']
action = @rpc[which]
result = action.call(params)
render :json => result.to_json
end
його використання має бути очевидним з коду
class GeoLocationController < ApplicationController
rpc(:geo_location) do |params|
geo_location = GeoLocation.geo_locate( params['address'] )
geo_location.attributes
end
rpc(:lat_lng) do |params|
geo_location = GeoLocation.geo_locate( params['address'] )
{ 'lat' => geo_location.lat, 'lng' => geo_location.lng }
end
end
використання з JS вимагає двох речей: маршруту та невеликого класу JS. спочатку маршрут:
match ':controller#rpc', :action => 'rpc'
далі, JS, також тут -> https://gist.github.com/ahoward/7320900
переглядаючи це, ви побачите, що використання бекенд-дій rpc з JS таке ж просте, як
var rpc = new RPC(url);
rpc.call('geo_location', params, callback);
зазвичай, внизу перегляду ми просто створюємо об'єкт rpc для сторінки з відносним URL
<script>
jQuery(function(){
var rpc = new RPC(<%= raw url_for(:action => :rpc).to_json %>);
});
</script>
і ми розпочинаємо.
отже, ось воно - простий спосіб утримати ваші допоміжники JS rpc від забруднення ваших контролерів та переглядів різними стратегіями, і ще один приклад того, як наявність брутально послідовних інтерфейсів робить абстракцію можливою та простою.
оновлення: весь підхід можна узагальнити так
class BaseController
RPC = Hash.new
def self.rpc(method_name, &block)
RPC[method_name