Dan Weaver
Dan Weaver

Reputation: 731

How to override default_scope in client_side_validations gem?

I have default_scope on most of my models that scopes by current_user.company. I'm using the client_side_validations gem on my sign up page which means there is no tenant set.

When the uniqueness validator runs on @user.email the default_scope prevents the validation from running properly (because company_id is nil) and therefore always looks like a unique result.

My user model:

# user.rb
...
default_scope { where(company_id: Company.current_id) }
...

This query is run when validating email:

Started GET "/validators/uniqueness?case_sensitive=true& \
user%5Bemail%5D=me%2B40%40example.com&_=1423897339854" \
for 76.175.168.2 at 2015-02-14 07:02:30 +0000                        
  User Exists (0.4ms)  SELECT 1 AS one FROM "users" WHERE \
  "users"."company_id" IS NULL AND "users"."email" = '[email protected]' LIMIT 1

When I remove the default_scope from my user model I get the correct result and proper validation:

Started GET "/validators/uniqueness?case_sensitive=true& \
user%5Bemail%5D=me%2B40%40example.com&_=1423897339854" \
for 76.175.168.2 at 2015-02-14 07:02:30 +0000
  User Exists (0.4ms)  SELECT 1 AS one FROM "users" WHERE \
  "users"."email" = '[email protected]' LIMIT 1

What's the most practical way for me to override the default_scope when this gem runs the email validator?

Upvotes: 0

Views: 236

Answers (3)

Dan Weaver
Dan Weaver

Reputation: 731

I ended up money patching the gem within my app to fix my issue. I'll also submit the change to the gem author since I'm not sure if this is a bug or their original desired behaviour.

# lib/client_side_validations/active_record/middleware.rb

def self.is_unique?(klass, attribute, value, params)
  ...
  !klass.where(relation).exists?
end

# patched the above line to: !klass.unscoped.where(relation).exists?

Upvotes: 0

Piotr Karbownik
Piotr Karbownik

Reputation: 201

Generally i would say: don't use default_scope cause you will run to all sorts of problems like this. Default scope is okay for ordering in my opinion.

But here you can solve it like this:

class User < ActiveRecord::Base
 def self.default_scope
    #i don't know what company represents here
    where(company_id: Company.current_id) if Company.present?
 end
end

You can define default scope as class method like you see above.

See doc: http://apidock.com/rails/ActiveRecord/Base/default_scope/class

Upvotes: 1

jerrytao
jerrytao

Reputation: 156

I don't think override the default_scope is a good idea.

You should move the logic to controller. I don't know if you are using pundit. It will provider a scope function.

If not, try to move this scope to controller.

def current_users
   @users||= User.where(company_id: Company.current_id)
end

Upvotes: 0

Related Questions