私は、テストのために未加工の投稿データ(例:パラメータ化されていないJSON)をコントローラーの1つに送信したいと考えています。
class LegacyOrderUpdateControllerTest < ActionController::TestCase
test "sending json" do
post :index, '{"foo":"bar", "bool":true}'
end
end
しかし、これは私にNoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>
エラーを与えます。
ActionController::TestCase
で生の投稿データを送信する正しい方法は何ですか?
コントローラーコードは次のとおりです。
def index
post_data = request.body.read
req = JSON.parse(post_data)
end
今日同じ問題に出くわし、解決策を見つけました。
test_helper.rb
で、ActiveSupport::TestCase
内で次のメソッドを定義します。
def raw_post(action, params, body)
@request.env['RAW_POST_DATA'] = body
response = post(action, params)
@request.env.delete('RAW_POST_DATA')
response
end
機能テストでは、post
メソッドと同じように使用しますが、3番目の引数として生の投稿本文を渡します。
class LegacyOrderUpdateControllerTest < ActionController::TestCase
test "sending json" do
raw_post :index, {}, {:foo => "bar", :bool => true}.to_json
end
end
私はこれをRails 2.3.4を使用して未加工の投稿本文を読み取るときにテストしました
request.raw_post
の代わりに
request.body.read
ソースコード を見ると、raw_post
がrequest.body.read
をラップし、request
envでこのRAW_POST_DATA
をチェックしていることがわかります。ハッシュ。
実際に、rspec post要求をシミュレートする前に1行追加するだけで同じ問題を解決しました。あなたがすることは、「RAW_POST_DATA」を投入することです。 post:createで属性varを削除しようとしましたが、削除してもアクションが見つかりません。
ここで私の解決策。
def do_create(attributes) request.env ['RAW_POST_DATA'] = attributes.to_json post:create、attributes end
コントローラでは、JSONを読み取るために必要なコードは次のようなものです
@property = Property.new(JSON.parse(request.body.read))
テストを実行しているスタックトレースを見ると、リクエストの準備をより細かく制御できます:ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session.env_for
Json文字列を:paramsとして渡し、コンテンツタイプ「application/json」を指定できます。それ以外の場合、コンテンツタイプは「application/x-www-form-urlencoded」に設定され、jsonは適切に解析されます。
したがって、必要なのは「CONTENT_TYPE」を指定することだけです。
post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json'
Rails5 +統合テストを使用している場合、これを行う(文書化されていない)方法は、params引数に文字列を渡すことです。
post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' }
Rails 5のバージョン:
post :create, body: '{"foo": "bar", "bool": true}'
here を参照してください。body
文字列パラメーターは、未加工の要求本文として扱われます。
RSpec(> = 2.12.0)を使用してリクエスト仕様を記述している場合、含まれるモジュールはActionDispatch::Integration::Runner
。ソースコードを見ると、 post メソッドが process を呼び出し、rack_env
パラメータ。
これはすべて、仕様で次のことを簡単に行えることを意味します。
#spec/requests/articles_spec.rb
post '/articles', {}, {'RAW_POST_DATA' => 'something'}
そしてコントローラーで:
#app/controllers/articles_controller.rb
def create
puts request.body.read
end
Rails 4、
raw_xml = File.read("my_raw.xml")
post :message, raw_xml, format: :xml
提供されたパラメーターが文字列である場合、本体としてコントローラーに渡されるだけだと思います。
post
メソッドは、名前と値のペアのハッシュを想定しているため、次のようにする必要があります。
post :index, :data => '{"foo":"bar", "bool":true}'
次に、コントローラーで、次のように解析するデータを取得します。
post_data = params[:data]
Rails 4.1.5の時点で、これが私のために働いた唯一のものでした:
class LegacyOrderUpdateControllerTest < ActionController::TestCase
def setup
@request.headers["Content-Type"] = 'application/json'
end
test "sending json" do
post :index, '{"foo":"bar", "bool":true}'.to_json, { account_id: 5, order_id: 10 }
end
end
/ accounts/5/orders/10/itemsのURL。これにより、JSON本体と同様に伝達されるurlパラメーターが取得されます。もちろん、注文が埋め込まれていない場合は、paramsハッシュを省略できます。
class LegacyOrderUpdateControllerTest < ActionController::TestCase
def setup
@request.headers["Content-Type"] = 'application/json'
end
test "sending json" do
post :index, '{"foo":"bar", "bool":true}'.to_json
end
end
Rails 5.1では、本文のデータを必要とする削除要求を行うときに次のように機能します。
delete your_app_url, as: :json, env: {
"RAW_POST_DATA" => {"a_key" => "a_value"}.to_json
}
注:これは、統合テストを行う場合にのみ機能します。
統合テスト(Rails 5.1)で生のJSONコンテンツを投稿する方法を探していました。私のソリューションもこの場合に役立つと思います。 post
メソッドのドキュメントとソースコードを検索しました。 https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/RequestHelpers.html#method-i- post
これにより、詳細についてprocess
メソッドに導かれました。 https://api.rubyonrails.org/v5.1/classes/ActionDispatch/Integration/Session.html#method-i-process
これにより、process
、したがってpost
メソッドで受け入れられるパラメーターが最終的にわかりました。最終的な解決策は次のとおりです。
post my_url, params: nil, headers: nil, env: {'RAW_POST_DATA' => my_body_content}, as: :json