Ruby on Rails - beware of default scope in ruby on rails - ruby on rails tutorial - rails guides - rails tutorial - ruby rails



ActiveRecord includes default_scope, to automatically scope a model by default.

class Post
  default_scope ->{ where(published: true).order(created_at: :desc) }
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Above code will serve posts which are already published when we perform any query on the model.
Post.all # will only list published posts 
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • That scope, while innocuous-looking, has multiple hidden side-effect that we may not want.
  • default_scope and order
  • Since we declared an order in the default_scope, calling order on Post will be added as additional orders instead of overriding the default.
Post.order(updated_at: :desc)
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
SELECT "posts".* FROM "posts" WHERE "posts"."published" = 't' ORDER BY "posts"."created_at" DESC, "posts"."updated_at" DESC
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

default_scope and model initialization

  • With any other ActiveRecord::Relation, default_scope will alter the default state of models initialized from it.
  • Above example, Post has where(published: true) set by default, and so new models from Post will also have it set.
Post.new # => <Post published: true>
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

unscoped

  • default_scope can nominally be cleared by calling unscoped first, but this also has side-effects.

Example

class Post < Document
  default_scope ->{ where(published: true).order(created_at: :desc) }
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

Default, queries against Post will be scoped to type columns containing 'Post". But unscoped will clear this along with our own default_scope, so if we use unscoped we have to remember to account for this as well.

Post.unscoped.where(type: 'Post').order(updated_at: :desc)
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

unscoped and Model Associations

Assume a relationship between Post and User

class Post < ApplicationRecord
  belongs_to :user
  default_scope ->{ where(published: true).order(created_at: :desc) }
end

class User < ApplicationRecord
  has_many :posts
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • Getting an individual User.
  • We can see the posts related to it:
user = User.find(1)
user.posts
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
SELECT "posts".* FROM "posts" WHERE "posts"."published" = 't' AND "posts"."user_id" = ? ORDER BY "posts"."created_at" DESC [["user_id", 1]]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • But we want to clear the default_scope from the posts relation, so we use unscoped.
user.posts.unscoped
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
SELECT "posts".* FROM "posts"
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team

This wipes out the user_id condition as well as the default_scope.

Example

  • There are situations where using default_scope is justifiable.
  • Assume a multi-tenant system where multiple subdomains are served from the same application but with isolated data. One way to achieve this isolation is through default_scope.
  • The downsides in other cases become upsides here.
class ApplicationRecord < ActiveRecord::Base
  def self.inherited(subclass)
    super

    return unless subclass.superclass == self
    return unless subclass.column_names.include? 'tenant_id'

    subclass.class_eval do
      default_scope ->{ where(tenant_id: Tenant.current_id) }
    end
  end
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
  • All we need to do is set Tenant.current_id to something early in the request, and any table that contains tenant_id will automatically become scoped without any additional code. Instantiating records will automatically inherit the tenant id they were created under.
  • The important thing about this use-case is that the scope is set once per request, and it doesn't change. The only cases we will need unscoped here are special cases like background workers that run outside of a request scope.

This ruby on rails tutorial page provides you the following key areas such as ruby , rail , ruby on rails , rail forum , ruby on rails tutorial , ruby tutorial , rails guides , rails tutorial , learn ruby , rails form_for , ruby rails , ruby class , what is ruby on rails , rails installer , ruby online , learn ruby on rails , ruby on rails jobs , rails find_by , install rails , easyrail , rubyonrails , link_to rails , ruby on rails developer , learn ruby the hard way , railscasts , ruby on rails examples , ruby on rails vs php , rails 4 , rails activerecord , rails generate , ruby and rails , ruby on rails download , install ruby on rails , ruby net http , what is rails , ruby app , ruby vs ruby on rails , ruby on rails windows , rails for zombies , ruby on rails book , ruby on rails development , ruby on rails ide , ruby on rails tutorial pdf

Related Searches to beware of default scope in ruby on rails