Test case with enum requires key after upgrade Rails from v4 to v5

Viewed 97

I am in the process of upgrading my Rails app from v4 to v5. When I run the tests, some of them fail which used to pass before.

For instance,

(enum)

enum session_type: {regular: 0, demo: 1, promotional: 2}

(usage)

session = {
          :uuid => SecureRandom.uuid,
          :session_type => 0,
}

post :create, :format => :json, params: { :session => session }

The parameter goes through a params.require(:session).permit(...)

'0' is not a valid session_type
/home/anz/.rvm/gems/ruby-2.2.3/gems/activerecord-5.0.0/lib/active_record/enum.rb:137:in `assert_valid_value'
/home/anz/.rvm/gems/ruby-2.2.3/gems/activerecord-5.0.0/lib/active_record/attribute.rb:67:in `with_value_from_user'
/home/anz/.rvm/gems/ruby-2.2.3/gems/activerecord-5.0.0/lib/active_record/attribute_set.rb:51:in `write_from_user'
/home/anz/.rvm/gems/ruby-2.2.3/gems/activerecord-5.0.0/lib/active_record/attribute_methods/write.rb:50:in `write_attribute_with_type_cast'
/home/anz/.rvm/gems/ruby-2.2.3/gems/activerecord-5.0.0/lib/active_record/attribute_methods/write.rb:32:in `write_attribute'
/home/anz/.rvm/gems/ruby-2.2.3/gems/activerecord-5.0.0/lib/active_record/attribute_methods/write.rb:20:in `__temp__3756373796f6e6f547970756='

When I use regular instead of 0, it works. What's going on?


UPDATE 1:

Doing so correctly parses the parameters

@request.env['CONTENT_TYPE'] = 'application/json'
post :create, :format => :json, params: { :session => session }

I tried as: :json, but it failed to work. I wonder why it is not working, looks way better than adding @request.env.

post :create, as: :json, params: { :session => session }

UPDATE 2: After updating rails from 5.0.0 to 5.0.7.2, as: :json is working.

post :create, as: :json, params: { :session => session }
1 Answers

Look carefully at the error message, it is complaining about '0', not 0.

If you try to set session_type to a string, then it is expecting 'regular', 'demo', or 'promotional'. If you use a number then it expects 0, 1, or 2. But ActiveRecord isn't clever enough to try converting a string to a number before seeing if you're passing a valid value so it just sees '0' is something that isn't in %w[regular demo promotional] and tells you that you're passing an invalid value.

So either fix up the clients to send in strings or adjust your argument parsing to map strings to numbers with something like this:

def model_params
  permitted = params.require(:session).permit(...)
  if(permitted[:session_type].in?(Model.session_types.values.map(&:to_s))
    permitted[:session_type] = permitted[:session_type].to_i
  end
  permitted
end
Related