无法获得与 activerecord 类型存储一起使用的唯一性验证

发布于 2025-01-12 19:59:28 字数 1482 浏览 1 评论 0原文

我们在 https://github.com 使用 activerecord-typedstore gem /byroot/activerecord-typedstore 表示“您可以使用任何 ActiveModel 验证器”。我能够让 validates :name,present: true 工作,但是 validates :name, uniqueness: true 给我错误 PG::UndefinedColumn代码>(见下文)。有谁知道我做错了什么?

class CreateWorkspaces < ActiveRecord::Migration[7.0]
  def change
    create_table :workspaces do |t|
      t.json :payload, null: false
    end
  end
end
class Workspace < ApplicationRecord
  typed_store :payload, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
    s.string :name
  end
  
  validates :name, presence: true
  validates :name, uniqueness: true
end
% rails c
Loading development environment (Rails 7.0.2.3)
irb(main):001:0> Workspace.create(name: 'Hello')
  TRANSACTION (0.2ms)  BEGIN
  Workspace Exists? (0.9ms)  SELECT 1 AS one FROM "workspaces" WHERE "workspaces"."name" = $1 LIMIT $2  [["name", "Hello"], ["LIMIT", 1]]
  TRANSACTION (0.2ms)  ROLLBACK
/Users/vince/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activerecord-7.0.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': PG::UndefinedColumn: ERROR:  column workspaces.name does not exist (ActiveRecord::StatementInvalid)
LINE 1: SELECT 1 AS one FROM "workspaces" WHERE "workspaces"."name" ...

We're using the activerecord-typedstore gem at https://github.com/byroot/activerecord-typedstore which says "You can use any ActiveModel validator". I'm able to get validates :name, presence: true to work but validates :name, uniqueness: true gives me the error PG::UndefinedColumn (see below). Does anyone know what I'm doing wrong?

class CreateWorkspaces < ActiveRecord::Migration[7.0]
  def change
    create_table :workspaces do |t|
      t.json :payload, null: false
    end
  end
end
class Workspace < ApplicationRecord
  typed_store :payload, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
    s.string :name
  end
  
  validates :name, presence: true
  validates :name, uniqueness: true
end
% rails c
Loading development environment (Rails 7.0.2.3)
irb(main):001:0> Workspace.create(name: 'Hello')
  TRANSACTION (0.2ms)  BEGIN
  Workspace Exists? (0.9ms)  SELECT 1 AS one FROM "workspaces" WHERE "workspaces"."name" = $1 LIMIT $2  [["name", "Hello"], ["LIMIT", 1]]
  TRANSACTION (0.2ms)  ROLLBACK
/Users/vince/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activerecord-7.0.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': PG::UndefinedColumn: ERROR:  column workspaces.name does not exist (ActiveRecord::StatementInvalid)
LINE 1: SELECT 1 AS one FROM "workspaces" WHERE "workspaces"."name" ...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱的十字路口 2025-01-19 19:59:28

根据评论,我同意这不是上例中使用 json 作为列类型的最佳方式。如果你仍然想这样做,根据@max的评论添加这个文件models/concerns/hash_uniqueness_validator.rb

class HashUniquenessValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    result = record.class.where("payload->>:attribute = :value", {attribute: attribute, value: value})
    result = result.where(options[:scope] => record[options[:scope]]) if options.key?(:scope)
    record.errors.add attribute, (options[:message] || "is not unique") unless result.count.zero?
  end
end

然后你可以这样做

class Workspace < ApplicationRecord
  typed_store :payload, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
    s.string :name
    s.string :url
  end
  
  validates :name, presence: true, hash_uniqueness: true
  validates :url,  presence: true, hash_uniqueness: { scope: :user_id)
end

I agree based on the comments that this isn't the best use of json as the column type in the example above. If you still want to do this, based on @max's comment add this file models/concerns/hash_uniqueness_validator.rb

class HashUniquenessValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    result = record.class.where("payload->>:attribute = :value", {attribute: attribute, value: value})
    result = result.where(options[:scope] => record[options[:scope]]) if options.key?(:scope)
    record.errors.add attribute, (options[:message] || "is not unique") unless result.count.zero?
  end
end

then you can do this

class Workspace < ApplicationRecord
  typed_store :payload, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
    s.string :name
    s.string :url
  end
  
  validates :name, presence: true, hash_uniqueness: true
  validates :url,  presence: true, hash_uniqueness: { scope: :user_id)
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文