Sobreescribir un ámbito predeterminado de Rails


Si tengo un modelo ActiveRecord:: Base con un ámbito predeterminado:

class Foo < ActiveRecord::Base

  default_scope :conditions => ["bar = ?",bar]

end

¿Hay alguna manera de hacer un Foo.find ¿sin usando las condiciones default_scope? En otras palabras, ¿puede anular un ámbito predeterminado?

Habría pensado que usar 'default' en el nombre sugeriría que era overridable, de lo contrario se llamaría algo así como global_scope, ¿verdad?

Author: edgerunner, 2009-12-02

8 answers

Respuesta corta: No uses default_scope a menos que realmente tengas que hacerlo. Probablemente estarás mejor con alcances con nombre. Dicho esto, puede usar with_exclusive_scope para anular el ámbito predeterminado si es necesario.

Echa un vistazo a esta pregunta para más detalles.

 141
Author: Pär Wieslander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:48

En los carriles 3:

foos = Foo.unscoped.where(:baz => baz)
 199
Author: Vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-17 15:04:37

Si todo lo que necesita es cambiar el orden definido en default_scope, puede usar reorder método .

class Foo < ActiveRecord::Base
  default_scope order('created_at desc')
end

Foo.reorder('created_at asc')

Ejecuta el siguiente SQL:

SELECT * FROM "foos" ORDER BY created_at asc
 95
Author: GuiGS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-12 12:26:45

Desde 4.1 puede utilizar ActiveRecord::QueryMethods#unscope para combatir el ámbito predeterminado:

class User < ActiveRecord::Base
  default_scope { where tester: false }
  scope :testers, -> { unscope(:where).where tester: true }
  scope :with_testers, -> { unscope(:where).where tester: [true, false] }
  # ...
end

Es actualmente posible unscope cosas como: :where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :having.

Pero aún así por favor evite usar default_scope si puede. Es por tu propio bien.

 40
Author: jibiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-16 14:03:45

Puede anular un ámbito predeterminado utilizando el método with_exclusive_scope. Entonces:

foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }
 14
Author: John Topley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-02 00:31:47

Rails 3 default_scope no parece ser anulado como en Rails 2.

Por ejemplo

class Foo < ActiveRecord::Base
  belongs_to :bar
  default_scope :order=>"created_at desc"
end

class Bar < ActiveRecord::Base
  has_many :foos
end

> Bar.foos
  SELECT * from Foo where bar_id = 2 order by "created_at desc";
> Bar.unscoped.foos
  SELECT * from Foo;  (WRONG!  removes the "has" relationship)
> Bar.foos( :order=>"created_at asc" )  # trying to override ordering
  SELECT * from Foo where bar_id = 2 order by "created_at desc, created_at asc"

En mi aplicación, usando PostgreSQL, el orden en el ámbito predeterminado GANA. Estoy eliminando todos mis default_scopes y codificándolo explícitamente en todas partes.

Trampas Rails3!

 5
Author: vanboom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-16 02:04:50

Con Rails 3 + se puede usar una combinación de unscoped y merge:

# model User has a default scope
query = User.where(email: "[email protected]")

# get rid of default scope and then merge the conditions
query = query.unscoped.merge(query)
 3
Author: santervo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-13 07:44:19

Bueno, siempre puedes usar el antiguo favorito find_by_sql con la consulta completa. Por ejemplo: Modelo.find_by_sql ("SELECT * FROM models WHERE id=123")

 2
Author: Ady Rosen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-26 10:49:21