当前位置:  开发笔记 > 后端 > 正文

在Rails中使用Postgres UUID时,在Join记录上创建,保存,更新和销毁

如何解决《在Rails中使用PostgresUUID时,在Join记录上创建,保存,更新和销毁》经验,为你挑选了1个好方法。

我正在创建uids

create_table :users, { id: false } do |t|
    t.uuid :uid, default: 'uuid_generate_v4()'
    ... other columns

self.primary_key = :uid在模型中设置.

一般情况下,这适用于ActiveRecord,我写has_manybelongs_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并验证所有的规格都在通过(虽然我留在补丁中).但是,当我删除补丁时(即重命名uidid没有修复它),它仍然失败.

编辑

为了回应一些评论,我尝试了activeuuidgem(我遇到了错误),并决定完全切换到ID.这基本上是为了简单起见,因为我有压力尽快启动这个应用程序.

不过,即使有这样的修复,我需要打补丁save,createupdate.实际上delete补丁不再有效,我不得不将其删除(依靠原始补丁).我肯定希望避免制作这些补丁,因此我保持赏金.



1> tw airball..:

有利弊,既保留iduuid.对于公开的JSON API uuid,使用ConcernsRails-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代,但我认为上面的答案有一个链接.

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有