pg_search icon indicating copy to clipboard operation
pg_search copied to clipboard

Multisearch not working on a model that uses UUID for a primary key

Open litch opened this issue 10 years ago • 7 comments

I have a model:

CREATE TABLE businesses (
    id uuid DEFAULT uuid_generate_v4() NOT NULL,
    slug character varying(255),
    name character varying(255),
    phone_number character varying(255),
    website character varying(255),
    description text,
    latitude numeric(9,6),
    longitude numeric(9,6)
);

And am able to do a single-model search with it:

  pg_search_scope :search_by_properties, :against => [:website, :name, :description]

But when I try to do a multi-search using the following:

  multisearchable :against => [:website, :name, :description]

I get errors on model creation. Attached is a log of where the actual object creation fails:

?> b = Business.create(name: "Foo")
   (0.2ms)  BEGIN
  SQL (7.2ms)  INSERT INTO "businesses" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", Tue, 19 Nov 2013 15:42:00 CST -06:00], ["name", "Foo"], ["updated_at", Tue, 19 Nov 2013 15:42:00 CST -06:00]]
  PgSearch::Document Load (0.9ms)  SELECT "pg_search_documents".* FROM "pg_search_documents" WHERE "pg_search_documents"."searchable_id" = $1 AND "pg_search_documents"."searchable_type" = $2 ORDER BY "pg_search_documents"."id" ASC LIMIT 1  [["searchable_id", "24c17e11-c6e6-4133-af42-36ae1b7f6651"], ["searchable_type", "Business"]]
  Business Load (1.1ms)  SELECT "businesses".* FROM "businesses" WHERE "businesses"."id" = $1 ORDER BY "businesses"."id" ASC LIMIT 1  [["id", 24]]
PG::InvalidTextRepresentation: ERROR:  invalid input syntax for uuid: "24"
: SELECT  "businesses".* FROM "businesses"  WHERE "businesses"."id" = $1  ORDER BY "businesses"."id" ASC LIMIT 1
   (0.2ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation: ERROR:  invalid input syntax for uuid: "24"
: SELECT  "businesses".* FROM "businesses"  WHERE "businesses"."id" = $1  ORDER BY "businesses"."id" ASC LIMIT 1
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:786:in `get_last_result'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:786:in `exec_cache'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:139:in `block in exec_query'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract_adapter.rb:435:in `block in log'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.1/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract_adapter.rb:430:in `log'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_query'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:891:in `select'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:24:in `select_all'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/querying.rb:36:in `find_by_sql'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/relation.rb:585:in `exec_queries'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/association_relation.rb:15:in `exec_queries'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/relation.rb:471:in `load'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/relation.rb:220:in `to_a'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/relation/finder_methods.rb:325:in `find_first'
... 35 levels...
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/transactions.rb:326:in `block in with_transaction_returning_status'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `block in transaction'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:210:in `within_new_transaction'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `transaction'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/transactions.rb:209:in `transaction'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/transactions.rb:323:in `with_transaction_returning_status'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/transactions.rb:270:in `block in save'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/transactions.rb:281:in `rollback_active_record_state!'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/transactions.rb:269:in `save'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.0.1/lib/active_record/persistence.rb:37:in `create'
    from (irb):5
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.1/lib/rails/commands/console.rb:90:in `start'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.1/lib/rails/commands/console.rb:9:in `start'
    from /Users/litch/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.1/lib/rails/commands.rb:62:in `<top (required)>'
    from bin/rails:4:in `require'
    from bin/rails:4:in `<main>'

litch avatar Nov 19 '13 21:11 litch

The pg_search_documents table uses the searchable_type and searchable_id columns as a polymorphic foreign key back to the original record. But in your database, those types are mismatched.

So I think you would either commit to using UUIDs for all searchable types, and migrate the searchable_id column to be of type uuid, or perhaps you could get away with using a string type instead. You'd need to be careful that the polymorphic association still works for all your various searchable models.

Let me know what you find out. This is an interesting problem, and a reasonable use case I'd like to be able to support.

nertzy avatar Nov 20 '13 16:11 nertzy

Oops, misclicked, didn't mean to close the issue.

nertzy avatar Nov 20 '13 16:11 nertzy

Thanks! Yes, I think that sounds good. I had just taken a quick stab at it, but if I decide to implement it (which I'm like 80% sure I will), I'll send it upstream.

litch avatar Nov 20 '13 18:11 litch

@litch please close this issue if you have found the solution. Feel free to share your final solution what worked for you, so others could learn. Thanks.

giedriusr avatar Feb 03 '15 15:02 giedriusr

@giedriusr I don't want this issue closed if it represents a real problem in the gem. This is supposed to work without a workaround.

nertzy avatar Feb 13 '15 18:02 nertzy

I think most people who are using uuids for keys are probably using them everywhere, it would be nice if there were just a note on the readme about needing to change the generated migration if that is the case.

For me I simply needed to change the t.belongs_to :searchable... line in the migration to include :type => :uuid before running it and was set.

jordonbiondo avatar Dec 10 '15 01:12 jordonbiondo

Seems to me it would be safer to have the searchable_id column be varchar and just use typecasting on index? I definitely don't have integers nor UUIDs for my records (they vary, naturally), but varchar is able to represent both.

arcreative avatar Jul 19 '19 02:07 arcreative