A has_many Bs where B has no primary key

China☆狼群 提交于 2019-12-10 14:28:43

问题


I've got models A and B; A has_many B, and B belongs_to A. So far, so good—except, I specify that B doesn't have a primary key. I don't plan to ever modify or delete individual B rows, and I expect to have several million to billion of them, so omitting the primary key will be really handy, space-wise.

The migration to create B's table looked like this:

class CreateBs < ActiveRecord::Migration
  def change
    create_table :bs, {:id => false} do |t|
      # … rest of fields …
    end
  end
end

Unfortunately, ActiveRecord disagrees; trying to create an A (that's right!) results in:

1.9.3p194 :001 > A.create!
   (0.3ms)  BEGIN
   (0.1ms)  ROLLBACK
ActiveRecord::UnknownPrimaryKey: ActiveRecord::UnknownPrimaryKey
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/reflection.rb:366:in `primary_key'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/reflection.rb:216:in `association_primary_key'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/has_many_association.rb:104:in `foreign_key_present?'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/association.rb:165:in `find_target?'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/collection_association.rb:332:in `load_target'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/collection_proxy.rb:44:in `load_target'
…

If you catch the exception, its message states:

"Unknown primary key for table bs in model B." 

(which would be because B has no primary key.)

I'd like to not have this issue! Is there any way?


回答1:


The culprit turned out to be a detail missing from the question—of course—and missing from my working memory:

class A < ActiveRecord::Base
  has_many :bs

  validates :bs, :presence => true
end

Though I thought nothing about it at the time, there was—among many other validations—a validation of the presence of bs. If you squint really hard at the full backtrace—which I was "helpful" enough to truncate in my original question, you see:

ActiveRecord::UnknownPrimaryKey: ActiveRecord::UnknownPrimaryKey
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/reflection.rb:366:in `primary_key'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/reflection.rb:216:in `association_primary_key'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/has_many_association.rb:104:in `foreign_key_present?'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/association.rb:165:in `find_target?'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/collection_association.rb:332:in `load_target'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/collection_proxy.rb:44:in `load_target'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activerecord-3.2.8/lib/active_record/associations/collection_proxy.rb:87:in `method_missing'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activemodel-3.2.8/lib/active_model/errors.rb:255:in `block in add_on_blank'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activemodel-3.2.8/lib/active_model/errors.rb:253:in `each'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activemodel-3.2.8/lib/active_model/errors.rb:253:in `add_on_blank'
        from /Users/annelicuss/.rvm/gems/ruby-1.9.3-p194/gems/activemodel-3.2.8/lib/active_model/validations/presence.rb:8:in `validate'
-------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^

The error occurs in active_model/validations/presence.rb! Removing this constraint is enough to get us going. It can't find the target of the validation, as it tries to use the primary key to do so, and hence fails bad.




回答2:


Hmm, that is very odd. For some reason, I cannot replicate the problem on my end given the information you posted. I created a new project, created an A model followed by a B model that references A, and ran the migrations. My B table does not have a primary key, and only a foreign key to A, as expected.

The only thing I can suggest is the following

Write your A model like this:

class A < ActiveRecord::Base
  has_many :b, :primary_key=>:myPrimaryKeyFunction # name this function whatever you want, other than :id of course
end

Then, in the B model, simply create the corresponding "myPrimaryKeyFunction" function.

Other than that, I'm not sure what else to suggest. What version of rails and which DB are you running?



来源:https://stackoverflow.com/questions/12018767/a-has-many-bs-where-b-has-no-primary-key

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!