code

Rails는 요청의 매개 변수에서 빈 배열을 nil로 변환합니다.

codestyles 2020. 12. 9. 08:11
반응형

Rails는 요청의 매개 변수에서 빈 배열을 nil로 변환합니다.


내 앱에는 일반적인 플랫 개체가 아닌 백본 모델이 있으며, 큰 중첩 개체이며 중첩 된 부분을 MySQL 데이터베이스의 TEXT 열에 저장합니다.

Rails API에서 JSON 인코딩 / 디코딩을 처리하여 일부가 문자열 화 된 JSON 텍스트로 저장되어 있어도 외부에서이 하나의 큰 중첩 JSON 객체를 POST / GET 할 수있는 것처럼 보이도록하고 싶었습니다.

그러나 Rails가 마술처럼 빈 배열을 nil값으로 변환하는 문제가 발생했습니다 . 예를 들어 다음을 게시하면 :

{
  name: "foo",
  surname: "bar",
  nested_json: {
    complicated: []
  }
}

내 Rails 컨트롤러에는 다음이 표시됩니다.

{
  :name => "foo",
  :surname => "bar",
  :nested_json => {
    :complicated => nil
  }
}

그래서 내 JSON 데이터가 변경되었습니다 ..

전에이 문제를 겪은 사람이 있습니까? Rails가 내 POST 데이터를 수정하는 이유는 무엇입니까?

최신 정보

그들이하는 곳은 다음과 같습니다.

https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb#L288

그리고 여기에 ~ 왜 그들이 그것을 하는가 :

https://github.com/rails/rails/pull/8862

이제 문제는 중첩 된 JSON API 상황에서이를 가장 잘 처리하는 방법입니다.


많은 검색 끝에 Rails 4.1에서 시작하여 deep_munge "기능"을 완전히 건너 뛸 수 있음을 발견했습니다.

config.action_dispatch.perform_deep_munge = false

문서를 찾을 수 없지만 여기에서이 옵션의 소개를 볼 수 있습니다 : https://github.com/rails/rails/commit/e8572cf2f94872d81e7145da31d55c6e1b074247

이렇게하면 보안 위험이 발생할 수 있습니다 ( https://groups.google.com/forum/#!topic/rubyonrails-security/t1WFuuQyavI).


최근에 알려진 알려진 문제인 것 같습니다 : https://github.com/rails/rails/issues/8832

빈 배열이 어디에 있는지 알고 있다면 항상 params[:...][:...] ||= []이전 필터에 있을 수 있습니다 .

또는 BackBone 모델을 JSON 메서드로 수정하여 JSON.stringify()게시되기 전에 nested_json 값을 명시 적으로 문자열 화하고 JSON.parsebefore_filter에서 사용하여 수동으로 다시 파싱 할 수 있습니다.

못 생겼지 만 작동합니다.


다음과 같이 직접 매개 변수를 다시 구문 분석 할 수 있습니다.

class ApiController
  before_filter :fix_json_params    # Rails 4 or earlier
  # before_action :fix_json_params  # Rails 5

  [...]

  protected

  def fix_json_params
    if request.content_type == "application/json"
      @reparsed_params = JSON.parse(request.body.string).with_indifferent_access
    end
  end

  private

  def params
    @reparsed_params || super
  end
end

이는 JSON 콘텐츠 유형의 요청을 찾고 요청 본문을 다시 구문 분석 한 다음 params메서드를 가로 채서 다시 구문 분석 된 매개 변수가있는 경우이를 반환하는 방식으로 작동합니다.


비슷한 문제가 발생했습니다.

빈 문자열을 배열의 일부로 전송하여 수정했습니다.

그래서 이상적으로 당신의 매개 변수는

{
  name: "foo",
  surname: "bar",
  nested_json: {
    complicated: [""]
  }
}

따라서 빈 배열을 보내는 대신 깊은 뭉침 프로세스를 우회하라는 요청에 항상 ( "")을 전달합니다.


Here's (I believe) a reasonable solution that does not involve re-parsing the raw request body. This might not work if your client is POSTing form data but in my case I'm POSTing JSON.

in application_controller.rb:

  # replace nil child params with empty list so updates occur correctly
  def fix_empty_child_params resource, attrs
    attrs.each do |attr|
      params[resource][attr] = [] if params[resource].include? attr and params[resource][attr].nil?
    end
  end

Then in your controller....

before_action :fix_empty_child_params, only: [:update]

def fix_empty_child_params
  super :user, [:child_ids, :foobar_ids]
end

I ran into this and in my situation, if a POSTed resource contains either child_ids: [] or child_ids: nil I want that update to mean "remove all children." If the client intends not to update the child_ids list then it should not be sent in the POST body, in which case params[:resource].include? attr will be false and the request params will be unaltered.


I ran into a similar issue and found out that passing an array with an empty string would be processed correctly by Rails, as mentioned above. If you encounter this while submitting a form, you might want to include an empty hidden field that matches the array param :

<input type="hidden" name="model[attribute_ids][]"/>

When the actual param is empty the controller will always see an array with an empty string, thus keeping the submission stateless.

참고URL : https://stackoverflow.com/questions/14647731/rails-converts-empty-arrays-into-nils-in-params-of-the-request

반응형