Apply scope on a different model than controller
hidr0 opened this issue ยท 6 comments
I am in a category_controller.
And a category has many category_content_refs
I have a category_content_ref scope in the category_content_ref model which is
scope :tag, -> {...}
I would like to do this thing
When I get a request on /category/some-category?tag=tag-name
apply_scopes(@category.category_content_refs)
I want to apply the scope tag
on the category_content_refs, is that possible?
@Hidroo did you ever figure this out?
@elijahmurray nope. Not even close.
Hi everyone, just to make sure we're on the same page: do you guys want to call a scope on a different entity from the controller - e.g. call the scope on category_content_refs
inside a category_controller
- or do you have multiple scopes in the same controller and you want to call some on category
and others on category_content_refs
?
@tegon I can't speak for everyone but for me personally, I'd love to do something like calling my Book
scopes in my Categories
controller in the event I am using book objects in the category controller. If that makes sense. Apologies if this can already be done and I overlooked this feature.
The way to get this behaviour is to organise your model scopes properly and "delegate" some scopes to the correct model.
Lets say we have two models: Book and Author
class Author
# schema: id, :name
has_many :books
end
class Book
# id, :title, :author_id
belongs_to :author
end
And a Books controller with an index action where you want to search by different fields
class BooksController
def index
#...
end
end
You're required to search books by:
- Book title
- Author name
You first have to think whose responsibility it is to search an author by name and a book by title. It's each class' responsibility to implement these scopes.
class Author
# schema: id, :name
has_many :books
scope :name_is, -> (arg) { where(name: arg) }
end
class Book
# id, :title, :author_id
belongs_to :author
scope :title_is, -> (arg) { where(title: arg) }
end
Now, if you want to search books by the author's name, you can do the following:
class Book
# id, :title, :author_id
belongs_to :author
scope :title_is, -> (arg) { where(title: arg) }
scope :author_name_is, -> (arg) { joins(:author).merge(Author.name_is(arg)) }
end
author_name_is
becomes a delegator of the message.
Now your controller can respond to author_name_is
which is a scope of book but delegates it's responsibility to the correct class.
class BooksController
has_scope :title_is
has_scope :author_name_is
def index
apply_scopes(Book)
end
end
Thanks for the detailed explanation @pinzonjulian ๐ ๐
I'll go ahead and close the issue, but please let me know if you are having any problem with setting it up, we could add some documentation around that to help.