Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cveneziani/query-objects-example
Example of rails app using Query Objects
https://github.com/cveneziani/query-objects-example
activerecord delegator query-objects rails
Last synced: about 2 months ago
JSON representation
Example of rails app using Query Objects
- Host: GitHub
- URL: https://github.com/cveneziani/query-objects-example
- Owner: cveneziani
- License: other
- Created: 2016-05-18T17:07:08.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2023-04-01T20:55:18.000Z (almost 2 years ago)
- Last Synced: 2023-07-31T12:36:15.670Z (over 1 year ago)
- Topics: activerecord, delegator, query-objects, rails
- Language: Ruby
- Homepage: http://courses.cecilitse.org/talks/query-objects-in-rails-apps.html
- Size: 148 KB
- Stars: 37
- Watchers: 1
- Forks: 7
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Query Objects - Example
This is an example of a rails application that defines and uses Query Objects.
## Getting started
Have a look at `app/queries/` folder.
3 implementations are provided:
* Delegating to ActiveRecord::Relation (default one)
* Delegating to ActiveRecord::Relation with chaining ActiveRecord conditions in between
* Extending ActiveRecord::Relation## Usage
### Defining a Query Object
```ruby
class ArtistQuery < BaseQuery
# defines the default model on which queries will be made
def self.relation(base_relation=nil)
super(base_relation, Artist)
end# a first scope
def available
where(available: true)
end# another scope
def by_genre(genre)
where(genre: genre)
end
end
```### Making queries
```ruby
ArtistQuery.relation
# => Returns all artists.
# Based on `all` relation provided by `ActiveRecord`).ArtistQuery.relation.available
# => Returns all available artists.
# Based on `available` scope method provided by `ArtistQuery`.ArtistQuery.relation.available.by_genre('Metal')
# => Returns all available Metal artists.
# Based on `available` and `by_genre(name)` scope methods provided by `ArtistQuery`.ArtistQuery.relation.available.by_genre('Metal').order(:name)
# => Returns all available metal artists ordered by name.
# Based on `available` and `by_genre(name)` scope methods provided by `ArtistQuery`
# and based on `order` method provided by `ActiveRecord`.awesome_label = Label.first
ArtistQuery.relation(awesome_label.artists).available
# => Returns all available artists for awesome label.
# Based on the following association: `label` has many `artists`.
```## Chaining with ActiveRecord conditions in between
By default, this feature is not provided.
```ruby
# PROVIDED
ArtistQuery.relation.available.order(:name)# NOT PROVIDED
ArtistQuery.relation.order(:name).available
# => NoMethodError:
# undefined method `available' for #
```To enable this feature - which isn't recommended - switch to the [second implementation](app/queries/chaining/base_query.rb).
### Why isn't it recommended?
The purpose of query objects is to extract scopes from models and to have relevant queries.
Thus introducing ActiveRecord conditions between relevant queries is an anti-pattern. Try to avoid this behaviour.## Tests
There are tests for the 3 implementations. To run the tests:
```
$ rspec
```## Benchmark
A benchmark is provided between 2 implementations: delegator (default one) and extend. Just run the following command:
```
$ rake benchmark
```### Results
```
Warming up --------------------------------------
delegator -- without model 12.047k i/100ms
delegator -- with model 15.510k i/100ms
extend -- without model 8.431k i/100ms
extend -- with model 8.397k i/100ms
Calculating -------------------------------------
delegator -- without model 170.047k (± 3.8%) i/s - 855.337k in 5.037890s
delegator -- with model 169.862k (± 3.5%) i/s - 853.050k in 5.029212s
extend -- without model 77.498k (±12.7%) i/s - 379.395k in 5.009203s
extend -- with model 81.004k (±14.7%) i/s - 394.659k in 5.005465sComparison:
delegator -- without model: 170047.0 i/s
delegator -- with model: 169862.0 i/s - same-ish: difference falls within error
extend -- with model: 81004.4 i/s - 2.10x slower
extend -- without model: 77497.9 i/s - 2.19x slower
```## Running the app
### Requirements
* Ruby 2.4+
* SQLite### Installation
```
$ bundle install
$ rake db:create db:migrate db:seed
```## Credits
Thanks to [Bert Goethals](http://bertg.be/) for his help in optimizing the Query Objects.
## License
This project is released under the WTFPL License.