apply_scopes on multiple resources
phlegx opened this issue · 5 comments
Hi!
I have an index view of accounts
on AccountsController
. My view shows two tables. One table shows the user list (subclass of Account
) and a second one shows the student list (subclass of Account
). Every table has an own search scope:
class AccountsController < ApplicationController
has_scope :u_search, :s_search, only: :index
def index
@users = apply_scopes(User).all
@students = apply_scopes(Student).all
end
...
On every subclass model I have implemented the scope:
class User < Account
scope :u_search, -> search { ... }
end
class Student < Account
scope :s_search, -> search { ... }
end
Problem
If parameter u_search
is present, the scope is applied also on Student
. But u_search
scope don't exists on model Student
. How can I remove or add scopes to apply_scopes
related to the model? Any idea?
Idea
One possible solution can be a if: :scope_exists?
.
class AccountsController < ApplicationController
has_scope :u_search, :s_search, only: :index, if: :scope_exists?
Solved
See following patch or pull request! The simplest way is that apply_scopes
ignores non existing scopes in the target (accounts). E.g. scope u_search
(user search) applied on students (scope u_search
is not defined in students) is ignored. Same thing with s_search
(satellite search) applied on users (scope s_search
is not defined in users) is ignored.
I have write a small patch. This code overwrites the method call_scope_by_type(type, scope, target, value, options)
of has_scope
. This code checks first, if the target responses to the scope. If the scope method is not present in the target returns the target. In other words: this code don't catch an error if the scope is not found in the target.
See commit: phlegx@f643811
See repo: https://github.com/phlegx/has_scope
# config/initializers/has_scope.rb
module HasScope
protected
# Call the scope taking into account its type.
def call_scope_by_type(type, scope, target, value, options) #:nodoc:
block = options[:block]
if type == :boolean && !options[:allow_blank]
block ? block.call(self, target) : target.respond_to?(scope) ? target.send(scope) : target
elsif value && options.key?(:using)
value = value.values_at(*options[:using])
block ? block.call(self, target, value) : target.respond_to?(scope) ? target.send(scope, *value) : target
else
block ? block.call(self, target, value) : target.respond_to?(scope) ? target.send(scope, value) : target
end
end
end
Sorry, I don't think has scope has been designed to apply to two resources on the same page as you are trying to use, and I'm not sure that just adding respond to checks is a good thing because we may no longer give feedback in case the developer adds a typo while coding a scope.
Maybe we need to give it more thought if we actually want to allow this multiple scopes to happen. Thanks.
OK. I think scopes on multiple resources can be very useful, in many cases.
+1 I have the same problem. Is it been fixed ?
I did an ugly hack like this:
has_scope :u_search do |controller, scope, value|
scope.class.to_s == 'User::ActiveRecord_Relation' ? scope.u_search : scope
end
Not fully tested obviously, worked on my case.