5
votes

I'm making a Rails app, and I'd like a controller to gracefully handle an improperly formatted request. So, ideally, the parameters hash would look like this:

{"user" => { "username"=>"user1212" } }

But if someone sends data that looks like this:

{"user" => "user1212" }

I want to be able to raise a descriptive error, preferably a ParameterMissing. Right now, my user_params method looks like this:

def user_params
   params.require(:user).require(:username)
end

But if params.require(:user) returns a string, as in the second example, I get a NoMethodError. I tried params[:owner].require(:username) but that gives a TypeError. I've tried a bunch of combinations of permit and require, but I haven't found a solution I like. Is there a nice, clean way to require that params[:user] be a hash?

2
Did you tried giving it like this params.require(:user).permit(:username)?Pavan
Yes, that raises a NoMethodError because params.require(:user) returns a string. Also, I'd like to require :username.frenchbread

2 Answers

3
votes

require returns the parameter or raises an error if the key isn't there so to get what you want I had to do the following:

def user_params
   params.require(:user).require(:username)
   params.require(:user).permit(:username)
end

note: order is important as you want the full parameter returned i.e. your user parameter so the permit statement needs to come last. And if you wanted some optional parameters like email you would do the following:

def user_params
   params.require(:user).require(:username)
   params.require(:user).permit(:username, :email)
end    
0
votes

If you just want to raise an ActionController::ParameterMissing instead of the NoMethodError, I guess you can do something like this:

raise ActionController::ParameterMissing.new(:username) if params.fetch(:user).is_a?(String)