Having spent an afternoon googling and testing, I am convinced there is a piece of rails magic missing, but have no idea where it is.
I have a test that replicates the error seen in production.
Rails 4.2.11.13
Using the protected_attributes gem (so not a strong parameters issue)
I successfully send a json request to an api controller, but it only creates an empty version of the payment_allocation parameter.
Controller...
class Api::V1::PaymentAllocationsController < Api::ApiController
def create
p request.content_type
p request.body.read
p params
p self._wrapper_options
end
end
The body of the request as seen in the controller...
"{\"amount\":123.33,\"transaction_type\":\"Transaction\",\"claim_number\":\"ABC-123\",\"resolved\":false,\"paid_on\":\"2000-01-01\"}"
The content type.... "application/json"
The resulting params object...
{"controller"=>"api/v1/payment_allocations", "action"=>"create", "payment_allocation"=>{}}
And I confirmed that all the necessary attributes are available to the options used by wrap_parameters
<struct ActionController::ParamsWrapper::Options name="payment_allocation",
format=[:json],
include=["paid_on", "amount", "resolved", "claim_number", "transaction_type"],
exclude=nil, klass=Api::V1::PaymentAllocationsController,
model=PaymentAllocation(id: integer, paid_on: date, claim_number: string, transaction_type: string, amount: decimal, resolved: boolean)>
The wrap_parameters initializer is like so...
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# Disable root element in JSON by default.
ActiveSupport.on_load(:active_record) do
self.include_root_in_json = false
end
And I have confirmed that the initializer is being called.
So wrap_parameters has the right class, the right attributes, etc, but does not actually set the parameter values in payment_allocation.
My best is guess is that something can't parse the json string, but JSON.parse for the above string returns this...
{"amount"=>123.33, "transaction_type"=>"Transaction", "claim_number"=>"ABC-123", "resolved"=>false, "paid_on"=>"2000-01-01"}
Happy for any hints.
(BTW, I have an app with the same code in the same version of rails that does not have this issue.)
Discovered the issue, or more correctly, my colleague did.
We are using Rails LTS to support some of our older applications and there is a configuration setting for LTS in the
application.rbfile.We had this set initially as...
From the LTS docs, we learned that one of the effects of this setting is that it disables parsing JSON requests into parameters.
Changing the setting to...
Enables parsing JSON requests into parameters, which is what Rails does naturally. And things are working as desired.