我正在创建uids
create_table :users, { id: false } do |t| t.uuid :uid, default: 'uuid_generate_v4()' ... other columns
并self.primary_key = :uid
在模型中设置.
一般情况下,这适用于ActiveRecord,我写has_many
和belongs_to
关联很好.但是,当跨越连接表时(即has_many ... through:
,我需要编写自定义SQL来获取记录.
我已经发现我一般可以通过编写自定义SQL来做到这一点,即 SELECT * FROM main_table JOIN join_table ON main_table.uid = cast(join_table.uid AS uuid) WHERE condition=true)
我刚刚意识到的ActiveRecord的create
,destroy
,save
并且update
不要在连接模型的工作.
我已修补了四种方法以便它们起作用,但这对我来说太复杂了,可能并不理想.这是我的补丁:
def save(*args) # save sometimes works if it is called twice, # and sometimes works the first time but says theres an error super(*args) unless (super(*args) rescue true) end
有时,save
发出ROLLBACK
第一次没有解释.然后它第二次工作.在其他情况下(我不确定为什么,可能在更新时),第一次成功通过,但如果第二次调用则引发TypeError.请参阅此处以获取有关此错误的另一个问题,该问题在使用uid而不是id时如何保存连接没有任何答案.这是我的其他(工作)补丁.
def create(*args) attrs = args[0] raise( ArgumentError, "invalid args to bucket list create" ) unless attrs.is_a?(Hash) bucket_list_photo = self.class.new( attrs ) bucket_list_photo.save bucket_list_photo = BucketListPhoto.find_by( bucket_list_uid: bucket_list_photo.bucket_list_uid, photo_uid: bucket_list_photo.photo_uid ) return bucket_list_photo end def update(*args) # similar bug to save attrs = args[0] raise( ArgumentError, "invalid args to bucket list update" ) unless attrs.is_a?(Hash) bucket_list_uid = self.bucket_list_uid photo_uid = self.photo_uid due_at = self.due_at self.destroy bucket_list_photo = self.class.new( { bucket_list_uid: bucket_list_uid, photo_uid: photo_uid, due_at: due_at }.merge(attrs) ) bucket_list_photo.save bucket_list_photo = self.class.find_by( photo_uid: photo_uid, bucket_list_uid: bucket_list_uid ) return bucket_list_photo # phew end def destroy # patching to fix an error on #destroy, #destroy_all etc. # the problem was apparently caused by custom primary keys (uids) # see /sf/ask/17360801/ # however a custom fix is implemented here deleted_uids = ActiveRecord::Base.connection.execute( "DELETE FROM bucket_list_photos WHERE uid='#{uid}' RETURNING uid" ).to_a.map { |record| record['uid'] } raise "BucketListPhoto not deleted" unless ( (deleted_uids.length == 1) && (deleted_uids.first == uid) ) ActiveRecord::Base.connection.query_cache.clear # since, the cache isnt updated when using ActiveRecord::Base.connection.execute, # reset the cache to ensure accurate values, i.e. counts and associations. end
我甚至self.primary_key = :uid
在所有模特中都确保了这一点.
我也尝试过替换uid
,id
并验证所有的规格都在通过(虽然我留在补丁中).但是,当我删除补丁时(即重命名uid
列id
没有修复它),它仍然失败.
编辑
为了回应一些评论,我尝试了activeuuid
gem(我遇到了错误),并决定完全切换到ID.这基本上是为了简单起见,因为我有压力尽快启动这个应用程序.
不过,即使有这样的修复,我需要打补丁save
,create
和update
.实际上delete
补丁不再有效,我不得不将其删除(依靠原始补丁).我肯定希望避免制作这些补丁,因此我保持赏金.
有利弊,既保留id
和uuid
.对于公开的JSON API uuid
,使用Concerns
Rails-ish实现.
应用程序/模型/ user.rb
class User < ActiveRecord::Base include UserConcerns::Uuidable end
应用程序/模型/顾虑/ user_concerns/uuidable.rb
module UserConcerns::Uuidable extend ActiveSupport::Concern included do before_save :ensure_uuid! end def ensure_uuid! self.uuid = generate_uuid if uuid.blank? end def generate_uuid # your uuid using uuid_generate_v4() here end def to_param uuid end end
上面的实现遗漏了uuid代,但我认为上面的答案有一个链接.