2009-04-10 8 views
91

Parece una pregunta muy simple, pero no la he visto en ninguna parte.¿Cómo clasifico automáticamente una relación has_many en Rails?

En los carriles si tiene:

class Article < ActiveRecord::Base 
    has_many :comments 
end 
class Comments < ActiveRecord::Base 
    belongs_to :article 
end 

Por qué no puedes ordenar los comentarios con algo así:

@article.comments(:order=>"created_at DESC") 

alcance Named funciona si necesita hacer referencia que sea mucho e incluso la gente hace cosas como esta:

@article.comments.sort { |x,y| x.created_at <=> y.created_at } 

Pero algo me dice que debería ser más simple. ¿Qué me estoy perdiendo?

+0

tener cuidado, que está utilizando un método inesperado: @ article.comments (recarga = false) es forzar una falta de caché (forzar la recarga de un re lation). Si proporciona un hash, es lo mismo que @ article.comments (true). No te olvides de usar .all (: order => '...'). Me rompí la pierna algunas veces. –

Respuesta

143

Se puede especificar el orden de clasificación de la colección desnudo con una opción en has_many sí:

class Article < ActiveRecord::Base 
    has_many :comments, :order => 'created_at DESC' 
end 
class Comment < ActiveRecord::Base 
    belongs_to :article 
end 

O, si quieres un método simple, no la base de datos de la clasificación , utilice sort_by:

article.comments.sort_by &:created_at 

Reunir ing esto con los métodos añadido ActiveRecord de pedido:

article.comments.find(:all, :order => 'created_at DESC') 
article.comments.all(:order => 'created_at DESC') 

su experiencia puede variar: las características de rendimiento de las soluciones anteriores cambiarán enormemente dependiendo de los datos de la forma en la que obtienes en el primer lugar y el que se Rubí' reutilizando para ejecutar su aplicación.

+0

Gracias, el "todo" es probablemente el más simple. ¡Buen material! –

+48

en Rails 4, la opción de pedido ha sido eliminada. Use una lambda '-> {order (created_at:: desc)}' en su lugar. Ver: http://stackoverflow.com/questions/18284606/deprecated-warning-for-rails-4-model-with-order –

+0

esto estaba en desuso con rails 4, ver http://stackoverflow.com/questions/18284606/ deprecated-warning-for-rails-4-has-many-with-order – bjelli

7

Si está utilizando Rails 2.3 y desea utilizar el mismo orden predeterminado para todas las colecciones de este objeto, puede usar default_scope para solicitar su colección.

class Student < ActiveRecord::Base 
    belongs_to :class 

    default_scope :order => 'name' 

end 

A continuación, si se llama a

@students = @class.students 

Ellos serán ordenados según su default_scope. TBH en un orden de sentido muy general es el único uso realmente bueno de los ámbitos predeterminados.

+0

A partir de Rails 4 esto no es compatible. Consulte esta solución para conocer la sintaxis correcta de Rails 4: http://stackoverflow.com/questions/18506038/rails-4-default-scope –

31

A partir de los carriles 4, puede hacer:

class Article < ActiveRecord::Base 
    has_many :comments, -> { order(created_at: :desc) } 
end 
class Comment < ActiveRecord::Base 
    belongs_to :article 
end 

Para que una relación has_many :through las cuestiones de orden argumento (que tiene que ser segundo):

class Article 
    has_many :comments, -> { order('postables.sort' :desc) }, 
      :through => :postable 
end 

Si siempre querrán acceso comentarios en el mismo orden, sin importar el contexto, también puede hacerlo a través de default_scope dentro de Comment como:

class Comment < ActiveRecord::Base 
    belongs_to :article 
    default_scope { order(created_at: :desc) } 
end 

Sin embargo, esto puede ser problemático para el reasons discussed in this question.

Antes de Rieles 4 se podría especificar order como una clave en la relación, como:

class Article < ActiveRecord::Base 
    has_many :comments, :order => 'created_at DESC' 
end 

Como Jim menciona también se puede utilizar sort_by después de que haya resultados inverosímiles aunque en cualquier conjunto de resultados de tamaño esto será significativamente más lento (y usa mucha más memoria) que hacer tu pedido a través de SQL/ActiveRecord.

Si usted está haciendo algo donde la adición de un orden predeterminado es engorroso por alguna razón o si desea anular su defecto, en ciertos casos, es trivial para especificar que en la propia acción de ir a buscar:

sorted = article.comments.order('created_at').all 
+0

¿Dónde puedo especificarlo en la acción de búsqueda? ¿Anulo un método en el modelo? – Wit

+0

@Wit - puede agregar '.order()' a la cadena de métodos, como en el último ejemplo. ¿Es esto lo que estás preguntando? –

+0

Lo siento. No puedo recordar lo que estaba tratando de lograr. – Wit

0

Y si tiene que pasar algunos argumentos adicionales como dependent: :destroy o lo que sea, debe anexar los queridos después de una lambda, así:

class Article < ActiveRecord::Base 
    has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy 
end 
Cuestiones relacionadas