Предоставление JSON в контроллере
Я читал книгу и в главе о контроллерах, когда рассказывал о вещах, для JSON у нее есть пример, подобный этому, но не вдаваясь в подробности, поэтому я не мог разобраться в увеличенной картине, что в этом примере подходит:
render :json => @projects, :include => tasks
А также пример использования JSONP с функциями обратного вызова:
render :json => @record, :callback => 'updateRecordDisplay'
Может кто-нибудь объяснить это?
Ответы
Ответ 1
Обычно вы возвращаете JSON либо потому, что:
A) Вы создаете часть/все ваше приложение как одностраничное приложение (SPA), и вам нужен ваш клиентский JavaScript, чтобы иметь возможность извлекать дополнительные данные без полной перезагрузки страницы.
или
B) Вы создаете API, который будут потреблять третьи стороны, и вы решили использовать JSON для сериализации ваших данных.
Или, возможно, вы едите свой собственный dogfood и делаете как
В обоих случаях render :json => some_data
предоставит JSON-ify предоставленные данные. Клавиша :callback
во втором примере нуждается в более подробном объяснении (см. Ниже), но это еще одна вариация в той же идее (возврат данных таким образом, что JavaScript может легко справиться.)
Почему :callback
?
JSONP (второй пример) - это способ обойти Same Origin Policy, который является частью каждой встроенной безопасности браузера. Если у вас есть API в api.yoursite.com
, и вы будете откладывать свое приложение от services.yoursite.com
, ваш JavaScript не будет (по умолчанию) иметь возможность делать запросы XMLHttpRequest
(XHR - aka ajax) от services
до api
. То, как люди пробирались вокруг этого ограничения (до того, как была завершена спецификация
вместо этого сервер отправит обратно:
valueOfCallbackHere({"name": "John", "age": 45})
Таким образом, клиентское JS-приложение могло бы создать тег script
, указывающий на api.yoursite.com/your/endpoint?name=John
, и иметь функцию valueOfCallbackHere
(которая должна быть определена на стороне клиента JS), вызываемая с данными из этого другое происхождение.)
Ответ 2
Что именно вы хотите знать? ActiveRecord имеет методы, которые сериализуют записи в JSON. Например, откройте консоль рельсов и введите ModelName.all.to_json
, и вы увидите вывод JSON. render :json
по существу вызывает to_json
и возвращает результат браузеру с правильными заголовками. Это полезно для вызовов AJAX в JavaScript, где вы хотите вернуть объекты JavaScript для использования. Кроме того, вы можете использовать опцию callback
, чтобы указать имя обратного вызова, который вы хотите вызвать через JSONP.
Например, скажем, у нас есть модель User
, которая выглядит так: {name: 'Max', email:' [email protected]'}
У нас также есть контроллер, который выглядит так:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
render json: @user
end
end
Теперь, если мы вызываем вызов AJAX с использованием jQuery следующим образом:
$.ajax({
type: "GET",
url: "/users/5",
dataType: "json",
success: function(data){
alert(data.name) // Will alert Max
}
});
Как вы можете видеть, нам удалось получить User с id 5 из нашего приложения rails и использовать его в нашем JavaScript-коде, потому что он был возвращен как объект JSON. Опция обратного вызова просто вызывает функцию JavaScript имени named, переданного с объектом JSON, в качестве первого и единственного аргумента.
Чтобы привести пример параметра callback
, посмотрите на следующее:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
render json: @user, callback: "testFunction"
end
end
Теперь мы можем запросить запрос JSONP следующим образом:
function testFunction(data) {
alert(data.name); // Will alert Max
};
var script = document.createElement("script");
script.src = "/users/5";
document.getElementsByTagName("head")[0].appendChild(script);
Мотивация использования такого обратного вызова, как правило, заключается в том, чтобы обойти защиту браузера, которая ограничивает совместное использование ресурсов скрещиванием (CORS). Однако JSONP больше не используется, потому что существуют другие методы для обхода CORS, которые являются более безопасными и более легкими.
Ответ 3
Для экземпляра
render :json => @projects, :include => :tasks
Вы заявляете, что хотите рендерить @projects
как JSON и включить в экспортированную информацию ассоциацию tasks
в модели Project.
Для экземпляра
render :json => @projects, :callback => 'updateRecordDisplay'
Вы заявляете, что хотите отобразить @projects
как JSON и обернуть эти данные в javascript-вызов, который будет выглядеть примерно так:
updateRecordDisplay({'projects' => []})
Это позволяет отправлять данные в родительское окно и обходить проблемы подделки между сайтами.