Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ability to wrap "where" clause #519

Closed
noctivityinc opened this issue Feb 9, 2019 · 4 comments
Closed

add ability to wrap "where" clause #519

noctivityinc opened this issue Feb 9, 2019 · 4 comments

Comments

@noctivityinc
Copy link

Right now, when you call the API with a where statement -

User.where(name: 'Josh')

The server sees the request like this:

https://www.example.com/api/users?name=Josh

This is all well and good but if you have a large model and want to be able to filter on ANY of the attributes, you would need to create a complex method to handle the filtering (i.e. loop through all attributes and compare to the querystring to see if one of the keys match).

It would be cleaner if we could wrap the where filters in a root level attribute, like filter or whatever we want. So this:

User.where(name: 'Josh')

would appear like this:

https://www.example.com/api/users?filter[name]=Josh

and in the code we can check to see if the filter param was passed and all and then act ONLY on the keys passed.

@edtjones
Copy link
Collaborator

edtjones commented Feb 9, 2019

hi @noctivityinc there are a couple of ways to achieve this:

  • mix into Her::Model::Relation and redefine fetch
  • write a Faraday middleware to mutate the request before it hits your API, but after Her has finished with it.

Some examples:

Mutate parameters by redefining fetch in Her::Model::Relation - this is probably the closest to what you're describing:

https://github.com/rooftopcms/rooftop-ruby/blob/master/lib/rooftop/queries/queries.rb#L11

In this example we're mutating parameters to be inside a filter[] for a WordPress API endpoint. Her::Model::Relation is mixed into when the gem loads, here:

https://github.com/rooftopcms/rooftop-ruby/blob/f68ac881c77cfed4d53ee92780d8553ae9c7bb6a/lib/rooftop.rb#L147

Another example of redefining fetch - in this case to cache the results:

https://github.com/rooftopcms/rooftop-rails/blob/master/lib/rooftop/rails/relation_cache.rb#L8

Define a middleware to mutate parameters

This is lower-level. Here's an example - in this case we pass arguments into where in Her and then parse them out (and set other parameters) in a middleware. So you call Foo.where(something: bar, include_embedded_resources: true) and the request to the API endpoint is _embed.

https://github.com/rooftopcms/rooftop-ruby/blob/master/lib/rooftop/middleware/embed_middleware.rb

This particular example is to get around a limitation in Her that underscored arguments to where are parsed out so don't get to the API.

Hope this helps.

Ed

@noctivityinc
Copy link
Author

So continuing this thread, if we want to add our own class method, where exactly would we add it?

For example, if I want to add support for a limit method so:

User.limit(1) would call a defined method for all models inheriting the Her module, where would I do this?

@noctivityinc
Copy link
Author

Scratch that. I figured it out. For anyone else:

Add your method here:

Her::Model::Relation

and then define it as a class method here:

Her::Model::ORM::ClassMethods

So, for example, to add support for a limit method I did this in an initializer:

module Her
  module Model
    module ORM
      module ClassMethods
        [:limit].each do |method|
          class_eval <<-RUBY, __FILE__, __LINE__ + 1
            def #{method}(*params)
              scoped.send(#{method.to_sym.inspect}, *params)
            end
          RUBY
        end
      end
    end


    class Relation      
      def limit(num)
        return self if num.blank? && !@_fetch.nil?
        clone.tap do |r|
          r.params = r.params.merge({limit: num})
          r.clear_fetch_cache!
        end
      end
    end
end

@zacharywelch
Copy link
Collaborator

Glad you found a solution 😺 Normal usage for introducing common scopes would be inheritance or some sort of mixin. Is the monkey-patch based on your original need to override where? Be aware there's still an issue with scopes on associations.

Going to close this issue now. Please let us know if you have any further questions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants