heartcombo/has_scope

`default` option doesn't work when using `using`

TylerRick opened this issue · 2 comments

When I tried setting up a scope like this:

has_scope :status, in: :report_options, default: 'any'

and hitting the controller action without any params, I noticed it was generating status = NULL in the where conditions.

I was expecting it to generate status = 'any' by default since no params[:report_options][:status] is present.

When I dug deeper with a debugger, it's sending nil to the scope is because it value.values_at(*options[:using]) is indeed nil.

[159, 168] in gems/has_scope-0.7.2/lib/has_scope.rb
   159:     block = options[:block]
   160: 
   161:     if type == :boolean && !options[:allow_blank]
   162:       block ? block.call(self, target) : target.send(scope)
   163:     elsif value && options.key?(:using)
=> 164:       value = value.values_at(*options[:using])
   165:       block ? block.call(self, target, value) : target.send(scope, *value)
   166:     else
   167:       block ? block.call(self, target, value) : target.send(scope, value)
   168:     end

(byebug) value.values_at(*options[:using])
[nil]

I haven't dug any deeper yet to see how it's supposed to get the default value, but just wanted to report what I've found so far and suggest that it should probably be expected behavior for default to work with using too.

My workaround was to not use in: to tell has_scope to dig into the hash, but to use type: :hash and handle the digging into the hash and applying defaults manually myself in the block:

  has_scope :report_options, type: :hash do |controller, relation, hash|
    if value = hash[:active] || 'any'
      relation = relation.active(value)
    end
    ...
    relation
  end

The problem with doing it that way...

has_scope :report_options, type: :hash do |controller, relation, hash|
  ...

is that it doesn't even evaluate the block if params[:report_options] is not present, so it doesn't set defaults. Had to add a fake default value, default: {foo: 'foo'} just to force it to always evaluate the block...

So I think I'd rather have it working with each actual scope as its own declaration, with its own default value, instead of just having a single has_scope declaration for all of the scopes that are under this same top-level params key...

Hey @TylerRick, I opened #118 to hopefully fix this issue, and accept a proper default like you were originally trying.

Let me know if you are still able to test it out in your app, I plan to merge it and release a new version in a few days if all goes well. Thanks.