I am upgrading my Ruby 2.3.1 / Rails 4.2.5.1 to Rails 5.0.0.1 and I am encountering a strange error when running a controller spec for my following controller:
In my controller I have following code:
class Api::InboundSmsCallbackController < ActionController::Base
include Api::SmsCallbackHelpers
include Api::ServiceErrorHelpers
# GET /inbound_sms_callback/alert_acknowledgement(.:format)
def alert_acknowledgement
....
...
params.merge!({
acknowledger_user_id: acknowledger_user.id,
alert_id: alert.id,
acknowledgement_time: sms_sent_at
})
begin
creation_service = AcknowledgementAlert::CreationService.new(params)
rescue ServiceError => se
render json: json_hash, status: status
return
end
....
...
render json: json_hash, status: 200
end
end
After updating the bundle to use Rails 5, when I ran the controller code I got following warning:
DEPRECATION WARNING: Method merge! is deprecated and will be removed in Rails 5.1, as
ActionController::Parameters
no longer inherits from hash. Using this deprecated behavior exposes potential security problems. If you continue to use this method you may be creating a security vulnerability in your app that can be exploited. Instead, consider using one of these documented methods which are not deprecated: http://api.rubyonrails.org/v5.0.0.1/classes/ActionController/Parameters.html
To fix this I changed
params.merge!({
acknowledger_user_id: acknowledger_user.id,
alert_id: alert.id,
acknowledgement_time: sms_sent_at
})
TO
params = params.merge({
acknowledger_user_id: acknowledger_user.id,
alert_id: alert.id,
acknowledgement_time: sms_sent_at
})
and I am passing the params to my service class in following manner:
creation_service = AcknowledgementAlert::CreationService.new(params.to_unsafe_h)
But with that change when I run the spec example it fails with error saying
NoMethodError:
undefined method `merge' for nil:NilClass
and the error trace points to the line where I made the change:
params = params.merge({
acknowledger_user_id: acknowledger_user.id,
alert_id: alert.id,
acknowledgement_time: sms_sent_at
})
That is very weird because I tried printing params
before that statement is evaluated and I am getting an object printed:
>>>>>>>>>>>. params: <ActionController::Parameters {"message-timestamp"=>"2016-10-06 12:35:15 UTC", "msisdn"=>"919845128956", "text"=>"S3e9a6cE", "to"=>"12547836910", "controller"=>"api/inbound_sms_callback", "action"=>"alert_acknowledgement"} permitted: false>
Then why invoking merge
on params
is complaining about nil:NilClass.
I tried changing my updated code to
ackn_params = params.merge({
acknowledger_user_id: acknowledger_user.id,
alert_id: alert.id,
acknowledgement_time: sms_sent_at
})
creation_service = AcknowledgementAlert::CreationService.new(ackn_params.to_unsafe_h)
and it gets executed and my spec example passes.
I am not getting why then params = params.merge
doesn't work.
Does anybody has any idea on what is causing this weird behaviour?
Another thing I tried is:
params = params
ackn_params = params.merge({
acknowledger_user_id: acknowledger_user.id,
alert_id: alert.id,
acknowledgement_time: sms_sent_at
})
Now that fails with the same error
undefined method `merge' for nil:NilClass
So it looks like reassignment to params
is the root cause behind this. If this sounds correct then is there any specific reason why params
cannot be reassigned because documentation of ActionController::Parameters#merge(other_hash)
method says
Returns a new ActionController::Parameters with all keys from other_hash merges into current hash.
Thanks.