{"id":19156860,"url":"https://github.com/franckverrot/no_querying_views","last_synced_at":"2025-04-15T14:57:52.001Z","repository":{"id":1158584,"uuid":"1046128","full_name":"franckverrot/no_querying_views","owner":"franckverrot","description":"No more querying views in your Rails apps","archived":false,"fork":false,"pushed_at":"2020-09-05T23:26:18.000Z","size":15,"stargazers_count":59,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-28T21:23:41.097Z","etag":null,"topics":["activerecord","database","rails","sql"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/no_querying_views","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/franckverrot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-11-02T21:43:42.000Z","updated_at":"2024-12-05T11:27:55.000Z","dependencies_parsed_at":"2022-08-16T12:20:31.670Z","dependency_job_id":null,"html_url":"https://github.com/franckverrot/no_querying_views","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckverrot%2Fno_querying_views","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckverrot%2Fno_querying_views/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckverrot%2Fno_querying_views/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckverrot%2Fno_querying_views/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/franckverrot","download_url":"https://codeload.github.com/franckverrot/no_querying_views/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248573776,"owners_count":21126903,"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","database","rails","sql"],"created_at":"2024-11-09T08:36:09.875Z","updated_at":"2025-04-15T14:57:51.981Z","avatar_url":"https://github.com/franckverrot.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# No Querying Views\n\nThis gem will tell you when your team when they are querying the\ndatabase from a view.\n\nIt currently supports SQLite3 and PostgreSQL.\n\n\n## Requirements\n\n* Rails 5+\n\n\n## INSTALL\n\nManually, you can install the gem:\n\n    gem install no_querying_views\n\nIn your gemspec:\n\n    gem 'no_querying_views', '~\u003e 6.0.0'\n\n(There are no versions 3 to 6, I decided to align this gem's version with Rails\nmajor versions.)\n\n## Context\n\nRails is a MVC framework. The separation of concern should be respected\nto prevent bad things to happen in your application.\n\nExample: An order has N order lines. Each of these order lines has 1\nrelated item, and each of these items belongs to 1 category.\n\nIn Ruby code, your models would look like this:\n\n```ruby\n# app/models/order.rb\nclass Order \u003c ActiveRecord::Base\n  has_many :lines\nend\n\n\n# app/models/line.rb\nclass Line \u003c ActiveRecord::Base\n  has_one :item\nend\n\n\n# app/models/item.rb\nclass Item \u003c ActiveRecord::Base\n  belongs_to :category\nend\n\n\n# app/models/category.rb\nclass Category \u003c ActiveRecord::Base\nend\n```\n\nNow, if you want to display them on a single page, here is a naive version of\norder_controller.rb:\n\n```ruby\n# app/controllers/order_controller.rb\nclass OrderController \u003c ApplicationController\n  def show\n    @order = Order.find(params[:id])  # 1 query\n  end\nend\n```\n\nAnd a naive version of the views used to display the result:\n\n```ruby\n# app/views/orders/show.html.haml\n%h1\n  = @order.title\n%h2\n  %span Items\n  %ul\n    = render :partial =\u003e 'lines', :collection =\u003e order.lines   # 1 query, so far: 2 queries\n\n# app/views/orders/_lines.html.haml executed for **each single line**\n%li\n  %span\n    = line.item.title          # 1 query\n    = line.price\n  %div{:class =\u003e 'item_description'}\n    = line.item.description    # 0 query (cached)\n    = line.item.category       # 1 query\n```\n\n## The problem\n\nIf you use a tool that generates execution traces (like NewRelic RPM),\nyou will see that - for 1 order, 40 lines, 30 items, 20 categories - you will\nexecute:\n   1 (select * from order)\n+  1 (select * from lines inner join ... where order_id = foo)\n+ 40 (select * from items inner join ... where line.item_id = bar)\n+ 40 (select * from categories inner join ... where item.category_id = baz)\n ----\n  82 queries against the database!\n\nThis is called the [N + 1 problem](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) and it can be solved by an eager-loading strategy.\n\n\u003e \"Yeah, but my database is so small and so fast that I don't even see that!\"\n\nThis is true if you are the only user of the website.  But Rails will also have\ntroubles generating the page (HAML, ERB, whatever) and NewRelic won't tell you\nthat the queries are slowing down the application: the queries are fast as\nhell.\n\nThe combination of the rendering and the querying is slowing down the application, because:\n\n  1. Rendering a partial is slower than inline code\n  2. Executing a query costs time (retrieving the DB connection within\n     the pool, executing and fetching the results, ...): the resources\n     are not being used for free on your machine.\n\n## The solution\n\nSilver bullets don't exist, but most of the time you can speed up the\nperformance by eager-loading the data you expect in your views.\n\nFrom an architectural point of view, it is **wrong** to query the DB\nfrom a view. There are many reasons not to do so and the internet is\nfull of literature about it.\n\nRight now, here is a piece of code to help you remove any DB query from your\nviews.\n\n## What does this code do?\n\nIt will raise an exception everytime you and your people try to query the\ndatabase from within a view.\n\nIt only overrides the ``execute`` method of the adapter and checks the\ncall stack.\n\n## License\n\nMIT License. Copyright 2014 - Franck Verrot \u003cfranck@verrot.fr\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranckverrot%2Fno_querying_views","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranckverrot%2Fno_querying_views","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranckverrot%2Fno_querying_views/lists"}