ransack icon indicating copy to clipboard operation
ransack copied to clipboard

Error in schema validation with multi-tenant DB

Open gleopoldo opened this issue 3 years ago • 0 comments

Hello!

I got an intermittent error when querying a multitenant database using ransack:

RuntimeError:
            No table named messages exists.
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/adapters/active_record/context.rb:19:in `type_for'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/nodes/attribute.rb:35:in `type'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/nodes/condition.rb:266:in `default_type'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/nodes/condition.rb:25:in `extract'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/nodes/grouping.rb:175:in `write_attribute'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/nodes/grouping.rb:115:in `method_missing'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/search.rb:46:in `block in build'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/search.rb:42:in `each'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/search.rb:42:in `build'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/search.rb:34:in `initialize'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/adapters/active_record/base.rb:18:in `new'
          # ./.gems/ruby/2.7.0/gems/ransack-2.4.2/lib/ransack/adapters/active_record/base.rb:18:in `ransack'
          # ./app/services/message_reports/select.rb:10:in `paginated_data'

I tried to search the cause of this error and I fear that it should be related to how the schema cache is managed by a multi-tenant database - it seems to only be updated once the new schema is accessed by that connection. I tried to debug this issue placing a binding.pry before this line and tried the following:

[7] pry(#<Ransack::Adapters::ActiveRecord::Context>)> table
=> "messages"
[8] pry(#<Ransack::Adapters::ActiveRecord::Context>)> schema_cache.send(:data_source_exists?, table)
=> false
[9] pry(#<Ransack::Adapters::ActiveRecord::Context>)> Message.count
=> 2
[10] pry(#<Ransack::Adapters::ActiveRecord::Context>)> schema_cache.clear!
=> nil
[11] pry(#<Ransack::Adapters::ActiveRecord::Context>)> schema_cache.send(:data_source_exists?, table)
=> true

As you can see, the table actually exists, and can be accessed normally when doing Message.count, but the schema_cache is outdated. I'm not sure if this kind of validation is being used in other parts of the gem, but I'm wondering if ransack could just let the database adapter itself raise an error (such as PG::UndefinedTable, for example) instead of validating the database schema before the query is made. WDYT?

As a workaround for now, we added this line before the Message.ransack call, and for now it works fine:

      Message.connection.schema_cache.clear!

Here's my stack versions:

  • ruby: 2.7.2
  • rails: 6.0.3
  • ransack: 2.4.2

gleopoldo avatar Nov 05 '21 17:11 gleopoldo