簡體   English   中英

ActiveRecord Postgres適配器生成無效的SQL WHERE子句:WHERE(“ fieldname”)

[英]ActiveRecord Postgres adapter generating invalid SQL WHERE clause: WHERE(“fieldname”)

ActiveRecord 4.1.1在保存時生成了一些奇怪的SQL,而這些都是postgres遇到的:

SELECT  "projects".* FROM "projects"  WHERE ('uid') LIMIT 1
PG::InvalidTextRepresentation: ERROR:  invalid input syntax for type boolean: "uid"

我很確定這里引用的“布爾值”實際上是WHERE()語法,它期望布爾表達式作為參數。

uid被定義為模型的主鍵(請參見下文)...但是為什么在執行select_all時僅說WHERE('uid') (請參見stacktrace)? (為什么它在保存時執行select_all?)

Rails控制台

p = Project.new(name: "test", description: "test", workflow_id: 1)
=> #<Project name: "test", description: "test", user_id: nil, uid: nil, created_at: nil, updated_at: nil, workflow_id: 1, active: nil>
irb(main):031:0> p.save
   (1.9ms)  BEGIN
  Project Load (5.5ms)  SELECT  "projects".* FROM "projects"  WHERE ('uid') LIMIT 1
PG::InvalidTextRepresentation: ERROR:  invalid input syntax for type boolean: "uid"
LINE 1: SELECT  "projects".* FROM "projects"  WHERE ('uid') LIMIT 1
                                                     ^
: SELECT  "projects".* FROM "projects"  WHERE ('uid') LIMIT 1
   (1.7ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation: ERROR:  invalid input syntax for type boolean: "uid"
LINE 1: SELECT  "projects".* FROM "projects"  WHERE ('uid') LIMIT 1
                                                     ^
: SELECT  "projects".* FROM "projects"  WHERE ('uid') LIMIT 1
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:815:in `async_exec'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:815:in `block in exec_no_cache'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:373:in `block in log'
    from /app/vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.1/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract_adapter.rb:367:in `log'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:815:in `exec_no_cache'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_query'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/postgresql_adapter.rb:947:in `select'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:31:in `select_all'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/query_cache.rb:69:in `select_all'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/querying.rb:39:in `find_by_sql'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation.rb:603:in `exec_queries'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation.rb:487:in `load'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation.rb:231:in `to_a'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation/finder_methods.rb:451:in `find_take'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/relation/finder_methods.rb:98:in `take'
... 41 levels...
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `block in transaction'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:219:in `within_new_transaction'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:208:in `transaction'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:268:in `block in save'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:283:in `rollback_active_record_state!'
    from /app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:267:in `save'
    from (irb):31
    from /app/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:90:in `start'
    from /app/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/console.rb:9:in `start'
    from /app/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:69:in `console'
    from /app/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /app/vendor/bundle/ruby/2.0.0/gems/railties-4.1.1/lib/rails/commands.rb:17:in `<top (required)>'
    from /app/bin/rails:4:in `require'
    from /app/bin/rails:4:in `<main>

模型

class Project < ActiveRecord::Base

  self.primary_key = "uid"

end

ActiveRecord混合生成ID

module ActiveRecordUIDExtension
  extend ActiveSupport::Concern

    def generate_uid
      return unless self.class.column_names.include?("uid")
      self.id = SecureRandom.random_number(36**10).to_s(36)
      while !self.class.find_by(:uid, self.id).nil? do
       self.id = SecureRandom.random_number(36**10).to_s(36)
      end
  end
end

ActiveRecord::Base.send(:include, ActiveRecordUIDExtension)
ActiveRecord::Base.send(:before_create, :generate_uid)

Gemfile.lock

activerecord (4.1.1)
  activemodel (= 4.1.1)
  activesupport (= 4.1.1)
  arel (~> 5.0.0)

您的mixin沒有任何意義。 這部分正在導致錯誤的SQL:

self.class.find_by(:uid, self.id)

產生無效的SQL是因為您要告訴它。 find_by具有靈活的接口,因此必須進行一些解析才能查看您如何調用它。 當你說:

find_by(a, b)

參數解析可能假設您正在嘗試使用以下形式:

find_by('some_sql_snippet', placeholder_valid)

如本例中的文檔所示:

find_by("published_at < ?", 2.weeks.ago)

然后,它可能會to_s的第一個參數和掃描其中的占位符。 當你說:

find_by(:uid, self.id)

您將最終得到:uid.to_s並且self.id將被忽略,因為該字符串中沒有占位符。 這就可以解釋為什么您會在SQL中看到where ('uid')

修復mixin使其有意義:

self.class.find_by(:uid => self.id)

還是更好,切換到exists? 為了避免僅查看數據庫中是否存在一行而構建整個模型實例:

self.class.where(:uid => self.id).exists?
self.class.exists?(:uid => self.id)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM