ErwinM / acts_as_tenant

Easy multi-tenancy for Rails in a shared database setup.
MIT License
1.53k stars 262 forks source link

Issues with validates_uniqueness_to_tenant (TypeError: no implicit conversion of Symbol into Integer) #292

Open addisonmartin opened 1 year ago

addisonmartin commented 1 year ago

Hello I appear to be having a similar, although perhaps slightly different issue, to this open issue. Here's some information, let me know if you need anything else. Thank you all for your time on this great gem!

My Ruby version: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux] My Rails version: rails (7.0.3.1) My Acts as Tenant gem version: acts_as_tenant (0.5.1)

My organization.rb (my tenant model):

class Organization < ApplicationRecord
  has_many :users, inverse_of: :organization, dependent: :nullify

  validates :name, :subdomain, :domain, presence: true
  validates :name, :subdomain, :domain, uniqueness: true
end

My user.rb (from Devise):

class User < ApplicationRecord
  devise :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :validatable,
         :lockable, :timeoutable, :trackable

  acts_as_tenant(:organization)

  validates :username, presence: true
  validates_uniqueness_to_tenant :email, :username
end

With the code how it is, specifically the line in user.rb validates_uniqueness_to_tenant :email, :username running any rails db:* command causes an immediate error with Acts as Tenant Gem, backtrace follows:

** Invoke db:drop (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
rails aborted!
TypeError: no implicit conversion of Symbol into Integer
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/acts_as_tenant-0.5.1/lib/acts_as_tenant/model_extensions.rb:99:in `[]'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/acts_as_tenant-0.5.1/lib/acts_as_tenant/model_extensions.rb:99:in `validates_uniqueness_to_tenant'
~/Documents/oms/app/models/user.rb:80:in `<class:User>'
~/Documents/oms/app/models/user.rb:51:in `<main>'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:27:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activesupport-7.0.3.1/lib/active_support/inflector/methods.rb:280:in `const_get'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activesupport-7.0.3.1/lib/active_support/inflector/methods.rb:280:in `constantize'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activesupport-7.0.3.1/lib/active_support/core_ext/string/inflections.rb:74:in `constantize'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise.rb:320:in `get'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/mapping.rb:83:in `to'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/mapping.rb:78:in `modules'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/mapping.rb:95:in `routes'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/mapping.rb:162:in `default_used_route'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/mapping.rb:72:in `initialize'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise.rb:354:in `new'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise.rb:354:in `add_mapping'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/rails/routes.rb:243:in `block in devise_for'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/rails/routes.rb:242:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-4.8.1/lib/devise/rails/routes.rb:242:in `devise_for'
~/Documents/oms/config/routes.rb:6:in `block in <main>'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/actionpack-7.0.3.1/lib/action_dispatch/routing/route_set.rb:428:in `instance_exec'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/actionpack-7.0.3.1/lib/action_dispatch/routing/route_set.rb:428:in `eval_block'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/actionpack-7.0.3.1/lib/action_dispatch/routing/route_set.rb:410:in `draw'
~/Documents/oms/config/routes.rb:4:in `<main>'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:39:in `load'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:39:in `load'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/routes_reloader.rb:50:in `block in load_paths'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/routes_reloader.rb:50:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/routes_reloader.rb:50:in `load_paths'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/routes_reloader.rb:24:in `reload!'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/routes_reloader.rb:38:in `block in updater'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activesupport-7.0.3.1/lib/active_support/file_update_checker.rb:83:in `execute'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/routes_reloader.rb:13:in `execute'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application/finisher.rb:158:in `block in <module:Finisher>'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/initializable.rb:32:in `instance_exec'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/initializable.rb:32:in `run'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/initializable.rb:61:in `block in run_initializers'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:228:in `block in tsort_each'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:431:in `each_strongly_connected_component_from'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:349:in `block in each_strongly_connected_component'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:347:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:347:in `call'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:347:in `each_strongly_connected_component'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:226:in `tsort_each'
~/.rbenv/versions/3.1.2/lib/ruby/3.1.0/tsort.rb:205:in `tsort_each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/initializable.rb:60:in `run_initializers'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application.rb:372:in `initialize!'
~/Documents/oms/config/environment.rb:7:in `<main>'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:35:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application.rb:348:in `require_environment!'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/application.rb:511:in `block in run_tasks_blocks'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `block in execute'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `execute'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:243:in `block in invoke_prerequisites'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `invoke_prerequisites'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:243:in `block in invoke_prerequisites'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `invoke_prerequisites'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:188:in `invoke'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:160:in `invoke_task'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `block (2 levels) in top_level'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `each'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `block in top_level'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:125:in `run_with_threads'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:110:in `top_level'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/commands/rake/rake_command.rb:24:in `block (2 levels) in perform'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:186:in `standard_exception_handling'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/commands/rake/rake_command.rb:24:in `block in perform'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/rake_module.rb:59:in `with_application'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/commands/rake/rake_command.rb:18:in `perform'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/command.rb:51:in `invoke'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.3.1/lib/rails/commands.rb:18:in `<main>'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
~/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:drop => db:load_config => environment

But, if I change the line to validates_uniqueness_to_tenant :email or validates_uniqueness_to_tenant :username all rails db:* commands work correctly and as expected.

antonlitvinenko commented 1 year ago

While this is not fixed, you can use a workaround: just pass multiple attribute names as an array:

validates_uniqueness_to_tenant [:email, :username]