{"id":20923409,"url":"https://github.com/cveneziani/query-objects-example","last_synced_at":"2025-09-07T06:06:50.473Z","repository":{"id":8637027,"uuid":"59135667","full_name":"cveneziani/query-objects-example","owner":"cveneziani","description":"Example of rails app using Query Objects","archived":false,"fork":false,"pushed_at":"2023-04-01T20:55:18.000Z","size":152,"stargazers_count":38,"open_issues_count":5,"forks_count":7,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T04:47:13.854Z","etag":null,"topics":["activerecord","delegator","query-objects","rails"],"latest_commit_sha":null,"homepage":"http://courses.cecilitse.org/talks/query-objects-in-rails-apps.html","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cveneziani.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-18T17:07:08.000Z","updated_at":"2024-01-11T13:43:11.000Z","dependencies_parsed_at":"2023-02-11T22:02:22.129Z","dependency_job_id":null,"html_url":"https://github.com/cveneziani/query-objects-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cveneziani%2Fquery-objects-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cveneziani%2Fquery-objects-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cveneziani%2Fquery-objects-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cveneziani%2Fquery-objects-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cveneziani","download_url":"https://codeload.github.com/cveneziani/query-objects-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253981652,"owners_count":21994312,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","delegator","query-objects","rails"],"created_at":"2024-11-18T20:15:38.450Z","updated_at":"2025-05-13T16:30:36.553Z","avatar_url":"https://github.com/cveneziani.png","language":"Ruby","readme":"# Query Objects - Example\n\nThis is an example of a rails application that defines and uses Query Objects.\n\n## Getting started\n\nHave a look at `app/queries/` folder.\n\n3 implementations are provided:\n\n* Delegating to ActiveRecord::Relation (default one)\n* Delegating to ActiveRecord::Relation with chaining ActiveRecord conditions in between\n* Extending ActiveRecord::Relation\n\n## Usage\n\n### Defining a Query Object\n\n```ruby\nclass ArtistQuery \u003c BaseQuery\n  # defines the default model on which queries will be made\n  def self.relation(base_relation=nil)\n    super(base_relation, Artist)\n  end\n\n  # a first scope\n  def available\n    where(available: true)\n  end\n\n  # another scope\n  def by_genre(genre)\n    where(genre: genre)\n  end\nend\n```\n\n### Making queries\n\n```ruby\nArtistQuery.relation\n# =\u003e  Returns all artists.\n#     Based on `all` relation provided by `ActiveRecord`).\n\nArtistQuery.relation.available\n# =\u003e  Returns all available artists.\n#     Based on `available` scope method provided by `ArtistQuery`.\n\nArtistQuery.relation.available.by_genre('Metal')\n# =\u003e  Returns all available Metal artists.\n#     Based on `available` and `by_genre(name)` scope methods provided by `ArtistQuery`.\n\nArtistQuery.relation.available.by_genre('Metal').order(:name)\n# =\u003e  Returns all available metal artists ordered by name.\n#     Based on `available` and `by_genre(name)` scope methods provided by `ArtistQuery`\n#     and based on `order` method provided by `ActiveRecord`.\n\nawesome_label = Label.first\nArtistQuery.relation(awesome_label.artists).available\n# =\u003e  Returns all available artists for awesome label.\n#     Based on the following association: `label` has many `artists`.\n```\n\n## Chaining with ActiveRecord conditions in between\n\nBy default, this feature is not provided.\n\n```ruby\n# PROVIDED\nArtistQuery.relation.available.order(:name)\n\n# NOT PROVIDED\nArtistQuery.relation.order(:name).available\n# =\u003e  NoMethodError:\n#     undefined method `available' for #\u003cArtist::ActiveRecord_Relation:0x000000033208b8\u003e\n```\n\nTo enable this feature - which isn't recommended - switch to the [second implementation](app/queries/chaining/base_query.rb).\n\n### Why isn't it recommended?\n\nThe purpose of query objects is to extract scopes from models and to have relevant queries.\nThus introducing ActiveRecord conditions between relevant queries is an anti-pattern. Try to avoid this behaviour.\n\n## Tests\n\nThere are tests for the 3 implementations. To run the tests:\n\n```\n$ rspec\n```\n\n## Benchmark\n\nA benchmark is provided between 2 implementations: delegator (default one) and extend. Just run the following command:\n\n```\n$ rake benchmark\n```\n\n### Results\n\n```\nWarming up --------------------------------------\ndelegator -- without model 12.047k i/100ms\ndelegator -- with model    15.510k i/100ms\nextend -- without model     8.431k i/100ms\nextend -- with model        8.397k i/100ms\nCalculating -------------------------------------\ndelegator -- without model 170.047k (± 3.8%) i/s -    855.337k in   5.037890s\ndelegator -- with model    169.862k (± 3.5%) i/s -    853.050k in   5.029212s\nextend -- without model     77.498k (±12.7%) i/s -    379.395k in   5.009203s\nextend -- with model        81.004k (±14.7%) i/s -    394.659k in   5.005465s\n\nComparison:\ndelegator -- without model: 170047.0 i/s\ndelegator -- with model:    169862.0 i/s - same-ish: difference falls within error\nextend -- with model:        81004.4 i/s - 2.10x slower\nextend -- without model:     77497.9 i/s - 2.19x slower\n```\n\n## Running the app\n\n### Requirements\n\n* Ruby 2.4+\n* SQLite\n\n### Installation\n\n```\n$ bundle install\n$ rake db:create db:migrate db:seed\n```\n\n## Credits\n\nThanks to [Bert Goethals](http://bertg.be/) for his help in optimizing the Query Objects.\n\n## License\n\nThis project is released under the WTFPL License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcveneziani%2Fquery-objects-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcveneziani%2Fquery-objects-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcveneziani%2Fquery-objects-example/lists"}