modernistik / parse-stack

Parse Server Ruby Client SDK
https://www.modernistik.com/gems/parse-stack/
MIT License
60 stars 20 forks source link

Rails 6.1 breaks on "rake db:migrate" when parse-stack is included - TypeError: can't quote Parse::Operation #83

Open hunterae opened 7 months ago

hunterae commented 7 months ago

I have setup a simple demonstration app to show this issue: https://github.com/hunterae/rails6-1_parse-stack-issue

Essentially, when using Rails 6.1.6 (also confirmed with 6.1.7), and parse-stack 1.9.1 (also confirmed with 1.8.0), and mysql2 0.5.6 (also confirmed with 0.5.4), whenever you attempt to run "rake db:migrate", you get an error that says "TypeError: can't quote Parse::Operation".

The full error stack looks like this: /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/abstract/quoting.rb:240:in _quote' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/abstract/quoting.rb:20:inquote' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/collectors/substitute_binds.rb:20:in add_bind' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:699:invisit_Arel_Nodes_BindParam' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/visitor.rb:30:in visit' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:610:invisit_Arel_Nodes_Equality' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/visitor.rb:30:in visit' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:779:inblock in inject_join' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:777:in each' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:777:ineach_with_index' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:777:in inject_join' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:177:incollect_nodes_for' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:157:in visit_Arel_Nodes_SelectCore' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/mysql.rb:30:invisit_Arel_Nodes_SelectCore' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:124:in block in visit_Arel_Nodes_SelectStatement' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:123:ineach' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:123:in inject' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:123:invisit_Arel_Nodes_SelectStatement' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/mysql.rb:25:in visit_Arel_Nodes_SelectStatement' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/visitor.rb:30:invisit' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/visitor.rb:11:in accept' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/arel/visitors/to_sql.rb:18:incompile' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/abstract/database_statements.rb:37:in to_sql_and_binds' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/abstract/database_statements.rb:64:inselect_all' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/abstract/query_cache.rb:103:in select_all' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/mysql/database_statements.rb:12:inselect_all' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/querying.rb:47:in find_by_sql' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation.rb:843:inblock in exec_queries' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation.rb:861:in skip_query_cache_if_necessary' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation.rb:828:inexec_queries' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation.rb:631:in load' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation.rb:249:inrecords' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation/finder_methods.rb:524:in find_take' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation/finder_methods.rb:98:intake' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation/finder_methods.rb:81:in find_by' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/relation.rb:226:infind_or_initialize_by' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/querying.rb:22:in find_or_initialize_by' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/internal_metadata.rb:35:in[]=' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1310:in record_environment' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1303:inmigrate_without_lock' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1251:in block in migrate' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1401:inblock in with_advisory_lock' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1416:in block in with_advisory_lock_connection' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:462:inwith_connection' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1416:in with_advisory_lock_connection' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1397:inwith_advisory_lock' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1251:in migrate' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1086:inup' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/migration.rb:1061:in migrate' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/tasks/database_tasks.rb:237:inmigrate' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/railties/databases.rake:92:in block (3 levels) in <main>' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/railties/databases.rake:90:ineach' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/activerecord-6.1.7.6/lib/active_record/railties/databases.rake:90:in block (2 levels) in <main>' /Users/hunterae/.rvm/gems/ruby-2.7.8/gems/rake-13.1.0/exe/rake:27:in<top (required)>' /Users/hunterae/.rvm/gems/ruby-2.7.8/bin/ruby_executable_hooks:22:in eval' /Users/hunterae/.rvm/gems/ruby-2.7.8/bin/ruby_executable_hooks:22:in

' Tasks: TOP => db:migrate

hunterae commented 7 months ago

The gem also prevents upgrading to Rails 7.

hunterae commented 7 months ago

The issue seems to stem from the fact that the gem is dynamically defining "id" on Symbol. I added a fix by on my fork (https://github.com/hunterae/parse-stack) by hacking the method definition for Parse::Operation.register as follows (here's the commit: https://github.com/hunterae/parse-stack/commit/a0cdc652a106528fef43c3cec22d26350f47b39b):

module Parse
  class Operation
    def self.register(op, klass)
      Operation.operators[op.to_sym] = klass
      # Hack to get this working in Rails 6.1
      op = :object_id if op.to_sym == :id
      Symbol.send :define_method, op do |value = nil|
        operation = Operation.new self, op
        value.nil? ? operation : operation.constraint(value)
      end
    end
  end
end

I'm not making a PR for this commit as I imagine it breaks some of the existing functionality and I don't understand that portion of the functionality well enough to add a proper fix.