首页 > 解决方案 > 如何验证数据库,rails 6,postgres中是否已经存在列组合

问题描述

新手来了!

红宝石 2.7.1,宝石--版本 3.1.4,Rails 6.0.3.4

我的查询出现错误

def entry_uniqueness
    if Entry.where("lower(from) = ? AND lower(to) = ?",
                   from.downcase, to.downcase).exists?
      errors.add(:base, 'Identical combination already exists. YUP.')
    end
  end

错误:

PG::SyntaxError:错误:“来自”第 1 行或附近的语法错误:从“条目”WHERE 中选择 1 作为一个(lower(from)= 'here' A ... ^

完全错误

app/models/entry.rb:35:in entry_uniqueness' app/controllers/entries_controller.rb:9:in create' 开始 POST "/entries" for ::1 at 2021-02-13 16:17:47 +0800 由 EntriesController#create 作为 HTML 参数处理:{"authenticity_token"= >"98sjupNso6NW5xUonE/414I7ZvJQETMPBNWS+jcN+PffHaAJ3K0pdQofVPgnrBfflYn2SDXMlB17Q2G/gzideA==", "entry"=>{"translation"=>"1", "from"=>"here", "to"=>"there"}, " commit"=>"Post Translation"} [1m[36mEntry 存在吗?(10.2ms)[0m [1m[34mSELECT 1 AS one FROM "entries" WHERE (lower(from) = 'here' AND lower(to) = 'there') LIMIT $1[0m [["LIMIT", 1]] ↳ app/models/entry.rb:35:in `entry_uniqueness' Completed 500 Internal Server Error in 38ms (ActiveRecord: 10.2ms | Allocations: 2140)

ActiveRecord::StatementInvalid (PG::SyntaxError: 错误: "from" LINE 1 或附近的语法错误: SELECT 1 AS one FROM "entries" WHERE (lower(from) = 'here' A...^): app/模型/entry.rb:35:in entry_uniqueness' app/controllers/entries_controller.rb:9:in create'

错误信息


我想要实现的是:


| from  |  to   |
-----------------
| Here  | there |

=> 验证应该阻止用户添加heRE | THERE但可以添加THERE | heRE

:from:to在表中entries


注意:我尝试过作用域,它们在唯一性上起作用,但在不区分大小写时失败

validates_uniqueness_of :from, scope: :to

也试过

validates_uniqueness_of :from, :scope => :to, :case_sensitive => false

还尝试了 @r4cc00n 的实现,但它不起作用

scope :get_entries_by_from_and_to, ->(from, to) { where(arel_table[:from].lower.eq(from)).where(arel_table[:to].lower.eq(to))}
  validates_uniqueness_of :from, if: :entry_uniqueness?

  def entry_uniqueness?
    Entry.get_entries_by_from_and_to('from','to').nil?
  end

标签: ruby-on-railsrubyvalidationruby-on-rails-6

解决方案


fromPostgreSQL 中的保留名称。这很有意义,因为读取查询通常包含这个词(想想SELECT value FROM table)。因此,Rails 根据您的条件构建的查询

SELECT 1 AS one FROM "entries" WHERE (lower(from) = 'here' A...
                ^^^^                        ^^^^

混淆了数据库。顺便说一句to,它也是一个保留名称。

避免遇到此类问题的一种方法是,您应该考虑重命名该列。

另一个简单的解决方法是将列名用双引号括起来。只需将您的条件更改为:

Entry.exists?('lower("from") = ? AND lower("to") = ?', from.downcase, to.downcase)

请注意,我在列名周围使用了双引号,在整个条件周围使用了单引号。


推荐阅读