У меня есть приложение Rails 5.2, созданное только как API. Я использую Postman для тестирования конечных точек. В настоящее время я обертываю все свои JSON POSTS корневым элементом, чтобы он передавал «строгие параметры». Однако, согласно документам Rails, если wrap_parameters настроен на прием JSON, мне не нужно этого делать, однако мои POST-запросы терпят неудачу, если я этого не сделаю. Что я делаю неправильно?
# users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :update, :destroy]
.....
# POST /users
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created, location: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end
.....
private
.....
# Only allow a trusted parameter "white list" through.
def user_params
params.require(:user).permit(:email, :password, :is_admin, :is_agent)
end
end
# config/initializers/wrap_parameters.rb
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
Если я заверну JSON в user, он будет работать нормально, однако, согласно документации Rails, мне не нужно этого делать.
http://api.rubyonrails.org/v5.2.0/classes/ActionController/ParamsWrapper.html
Я пробовал добавлять wrap_parameters User, wrap_parameters :user и wrap_parameters format: [:json] непосредственно в users_controller.rb, но это ничего не дало.
Что я делаю неправильно?





Это из-за белый список параметров.
def user_params
params.require(:user).permit(:email, :password, :is_admin, :is_agent)
end
Здесь требуется ключ пользователя. С точки зрения безопасности, это хорошая функция в RoR для внесения параметров в белый список.
Если вы напишете только params.permit(:email, :password, :is_admin, :is_agent), то у вас будет работать тот же запрос, но удаление пользовательского объекта не рекомендуется.
Вы перезапустили свой сервер после создания файла инициализатора?
Да, я перезапускаю сервер после внесения любых изменений в любой код, даже если в этом нет необходимости. Я обнаружил, что это позволяет избежать головной боли. Однако инициализатор wrap_parameters по умолчанию уже находится в рельсах.
Это невероятно непоследовательно. Обертывания на продакшене, но не на тестировании или разработке. Параметр пропадает без следа.
@NathanCrause Я не мог понять, почему рельсы тоже не переносятся в тесте. Оказывается, это потому, что параметры не распознаются как json. Взгляните сюда stackoverflow.com/a/57451199
Я понял. Мне пришлось добавить wrap_parameters :user, include: %i[email password is_admin is_agent] в контроллер Users вот так:
# users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :update, :destroy]
wrap_parameters :user, include: %i[email password is_admin is_agent]
.....
# POST /users
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created, location: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end
.....
private
.....
# Only allow a trusted parameter "white list" through.
def user_params
params.require(:user).permit(:email, :password, :is_admin, :is_agent)
end
end
Я до сих пор не совсем понимаю, почему, но это работает. Документы подразумевают, что это должно происходить автоматически через модуль параметров переноса.
Все ли параметры, которые вы публикуете, существуют в виде столбцов в таблице User? В документах упоминается: «В моделях Active Record с установленным параметром no: include или: exclude он будет заключать в оболочку только параметры, возвращаемые методом класса attribute_names». Я сам постоянно сталкивался с этой проблемой, когда некоторые из моих параметров были перенесены, а некоторые нет. Оказывается, это была проблема. Чтение этого было очень полезным - api.rubyonrails.org/classes/ActionController/ParamsWrapper.h tml
После прочтения документации у меня сложилось впечатление, что вся суть модуля
wrap_parametersзаключается в том, что он автоматически обертывает ваши параметры с помощью объекта классов. Из документов:If you enable ParamsWrapper for :json format, instead of having to send JSON parameters like this: {"user": {"name": "Konata"}} You can send parameters like this: {"name": "Konata"}