7

Add option for `default_scope` to run on all queries

 3 years ago
source link: https://github.com/rails/rails/pull/40720
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Member

eileencodes commented 20 days ago

I'm open to other ways of achieving a set default scope / foreign key that gets applied to all queries for a model. In talking to @tenderlove this seemed to be the most straight forward way to achieve this since default scope already works for select/insert. We need this (or something like this) to use at GitHub for Vitess sharding (ie we want to add repository_id to sharded models for the primary vindex). I also talked to the Vitess folks over at planet scale and their monkey patch they've used for other Rails customers was very similar to extending default scope to include update/delete.


This change allows for applications to optionally run a default_scope
on update and delete queries. Default scopes already ran on select
and insert queries.

Applications can now run a set default scope on all queries for a model
by setting a all_queries option:

class Article < ApplicationRecord
  default_scope -> { where(blog_id: 1) }, all_queries: true
end

Using the default scope in this way is useful for applications that need
to query by more than the primary key by default. An example of this
would be in an application using a sharding strategy like Vitess.
For Rails sharding, we route connections first and then query the
database. However, Vitess and other solutions use a parameter in the
query to figure out how to route the queries. By extending
default_scope to apply to all queries we can allow applications to
optionally apply additional constraints to all queries. Note that this
only works with where queries as it does not make sense to select a
record by primary key with an order. With this change we're allowing
apps to select with a primary key and an additional foreign key.

To make this change dynamic for routing queries in a tenant sharding
strategy applications can use the Current API or parameters in a
request to route queries:

class Article < ApplicationRecord
  default_scope -> { where(blog_id: Current.blog.id) }, all_queries: true
end

In order to achieve this I created a new object when default scopes are
created. This allows us to store both the scope itself and whether we
should run this on all queries. I chose not to implement an on: option
that takes an array of actions because there is no simple or clear way
to turn off the default scope for create/select. It also doesn't really
make sense to only have a default scope for delete queries. The decision
to use all_queries here allows for the implementation to be more
flexible than it was without creating a mess in an application.

cc/ @rafaelfranca @tenderlove - I was wondering if this would benefit you at all Shopify with your sharding strategies.
cc/ @jhawthorn


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK