Q:

Rails 3.2: has_and_belongs_to_many - NameError when establishing association between two existing records

I have these three models:
class Cve < ActiveRecord::Base
  has_and_belongs_to_many :son_vulns
end

class Cpe < ActiveRecord::Base
  has_and_belongs_to_many :son_vulns
end

class SonVuln < ActiveRecord::Base
  has_and_belongs_to_many :cves
  has_and_belongs_to_many :cpes
end

I have join tables set up for each HABTM relationship named respectively:  cpe_son_vulns and cve_son_vulns.  These two join tables are identically structured.
In IRB this works fine:
> the-cpe = Cpe.first
> the-son-vuln.cpes << the-cpe

However, when I run the same sequence for the Cve model:
> the-cve = Cve.first
> the-son-vuln.cves << the-cve

I get this error:
NameError: uninitialized constant SonVuln::Cfe
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/activerecord-3.2.16/lib/active_record/inheritance.rb:111:in `compute_type'
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/activerecord-3.2.16/lib/active_record/reflection.rb:172:in `klass'
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/activerecord-3.2.16/lib/active_record/associations/collection_association.rb:148:in `transaction'
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/activerecord-3.2.16/lib/active_record/associations/collection_association.rb:134:in `concat'
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/activerecord-3.2.16/lib/active_record/associations/collection_proxy.rb:118:in `<<'
    from (irb):34
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/railties-3.2.16/lib/rails/commands/console.rb:47:in `start'
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/railties-3.2.16/lib/rails/commands/console.rb:8:in `start'
    from /Users/don/.rvm/gems/ruby-1.9.3-p484@sonsafe/gems/railties-3.2.16/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

I cannot understand why Rails is trying to generate a constant:  SonVuln::Cfe .  I've done a search in all my code and the sequence "cfe" appears no where. Why does Rails like Cpe but no Cve?  Any ideas on what Rails is trying to do here?

A:

I found that this was a problem with the Rails inflection rules.  It appears that Rails will  singularize any plural word that ends in "________ves" to a non-plural word that ends in "________fe".  This problem is difficult to find because Rails' inflection with pluralize a word that ends in "_________ve" to "________ves".
So in my case, Rails was taking my "Cve" class to the plural state: "Cves" and then singularizing that back to "Cfe".  Definitely not a symmetrical transformation!!!  This can be seen by using the console:
1.9.3p484 :001 > "cves".singularize
 => "cfe" 
1.9.3p484 :002 > "cve".pluralize
 => "cves" 

Here is the fix.  In config/initializers/inflections.rb I inserted this code:
ActiveSupport::Inflector.inflections do |inflect|
  inflect.clear :inflection_cfe
  inflect.irregular 'cve', 'cves'
end

I figured this out with help from this answer

