shoulda-matchers: ensure_inclusion_of does not work with polymorphic attributes

So I had ensure_inclusion_of working just fine, then I migrated some things to use FactoryGirl instead of explicit create statements and suddenly it’s failing. If I dup the object created by FactoryGirl, it works again. Here’s an example in my spec:

  before { @job_spec = FactoryGirl.create(:job_spec) }
  subject { @job_spec }

  it { should ensure_inclusion_of(:job_template_type).in_array(JobSpec::JOB_TEMPLATE_TYPES) }

  context "using a copy to get around ensure_inclusion_of bug" do
    before { @job_spec_dup = @job_spec.dup }
    subject { @job_spec_dup }

    it { should ensure_inclusion_of(:job_template_type).in_array(JobSpec::JOB_TEMPLATE_TYPES) }
  end

The first test fails, the second is successful:

JobSpec
  should ensure inclusion of job_template_type in ["TplBirstSoapGenericCommand", "TplBirstDuplicateSpace"] (FAILED - 1)
  using a copy to get around ensure_inclusion_of bug
    should ensure inclusion of job_template_type in ["TplBirstSoapGenericCommand", "TplBirstDuplicateSpace"]

Failures:

  1) JobSpec should ensure inclusion of job_template_type in ["TplBirstSoapGenericCommand", "TplBirstDuplicateSpace"]
     Failure/Error: it { should ensure_inclusion_of(:job_template_type).in_array(JobSpec::JOB_TEMPLATE_TYPES) }
     NameError:
       wrong constant name shouldamatchersteststring
     # ./spec/models/job_spec_spec.rb:19:in `block (2 levels) in <top (required)>'

Finished in 0.3576 seconds (files took 1.73 seconds to load)
15 examples, 1 failure

Failed examples:

rspec ./spec/models/job_spec_spec.rb:19 # JobSpec should ensure inclusion of job_template_type in ["TplBirstSoapGenericCommand", "TplBirstDuplicateSpace"]

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 15

Most upvoted comments

Still present in 2019. Will see if I can help.

If you’re testing a lot of models with polymorphic associations, you can use rspec helpers to DRY things up a bit:

# spec/support/model_helpers.rb

module ModelHelpers
  def all_models_except(*models)
    ApplicationRecord.subclasses.map(&:to_s) - models
  end
end

# spec/models/your_model.rb

it { should_not allow_value(*all_models_except('Foo', 'Bar').for(:whatever_type) }

No update, but if you can come up with a fix for this then we’d be happy to merge it in!

@amnesia7 Cool, thanks for reporting this 😃 This is definitely something we need help fixing.

Ah. So it looks like it’s failing because the attribute in question is polymorphic and thus ActiveRecord expects any value for this attribute to be a known class. I’ll mark this as a bug, but in the meantime you can use allow_value to get around this:

it { should allow_value(JobSpec::JOB_TEMPLATE_TYPES).for(:job_template_type) }

it do
  all_other_models = ActiveRecord::Base.subclasses.map(&:to_s) - JobSpec::JOB_TEMPLATE_TYPES
  should_not allow_value(*all_other_models).for(:job_template_type)
end