Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

default_scope in Sequel

In ActiveRecord there is a default_scope class method to specify a default scope. For example

class User < ActiveRecord::Base
  default_scope where(:deleted => false)
end

User.all # => SELECT * FROM users WHERE deleted = 0;

How can I do this in Sequel::Model?

EDIT:

After some googling I eventually found some useful information.

class User < Sequel::Model

  # Define some "scopes" (filters on the dataset)
  dataset_module do
    def existing
      filter(deleted: false)
    end

    def active
      filter(disabled: false)
    end
  end

  # This is the equivalent to a default_scope. Set one of the datasets
  # as the default dataset for this model.
  set_dataset(self.active)
end

The generated query then looks like this:

User.all # => SELECT * FROM `users` WHERE (`deleted` IS FALSE)

By the way: The equivalent to unscoped is unfiltered:

User.unfiltered.all # => SELECT * FROM `users`

But, there is one problem. If you try to update a user you got from an unfiltered dataset, it tries to update the user using the given dataset.

User.create(disabled: true, deleted: true)
User.all # => []
u = User.unfiltered.first # => Given user
u.disabled = false
u.save # => UPDATE users SET ... WHERE (disabled IS FALSE AND id = 1)
# => Sequel::NoExistingObject: Attempt to update object did not result in a single row modification

So I am back at the beginning. Any workaround for this?

like image 919
iblue Avatar asked Jul 26 '12 13:07

iblue


1 Answers

The best workaround is avoiding the problem by not having a default scope. In most cases a default scope is a bad idea. If you want most of your queries to use a scope, then apply the scope manually in those queries, don't use a default scope and try to backout the scope in other queries. A default scope only makes sense if all of your queries will use that scope.

You can also handle this by subclassing (User is not scoped, ActiveUser < User is scoped). However, I find the explicit scoping approach works better.

All that being said, if you really want to use a default scope, the following may work around the issue of updating a model instance outside the model's default scope:

User.instance_dataset.unfiltered!
like image 166
Jeremy Evans Avatar answered Oct 20 '22 11:10

Jeremy Evans