2010-10-29 15 views

Respuesta

30

Se produce un error debido a que están pidiendo su base de datos para realizar la ordenación.

@posts = Post.all.sort {|a,b| a.custom_method <=> b.custom_method}

Tenga en cuenta que esto se convierte en no trivial cuando se quiere empezar resultados de paginación y ya no desea a buscar .all. Piense en su diseño un poco antes de ir con esto.

+26

O un poco más simple que puede utilizar Post.all.sort_by (&: custom_method), logra el mismo resultado pero un poco más fácil para los ojos. – NZKoz

+0

Esto no parece funcionar si hay nils en su campo de comparación. ¿Hay una solución para esto? Tengo los siguientes valores 'display_rank' [10, 20, 30, nil, nil, nil, nil, nil, nil] esta declaración' Event.find (607) .event_staff_users.sort_by {| u | u.display_rank} 'da este error' ArgumentError: comparación de NilClass con 30 failed'. Encontré que usando 'event_staff_users.sort_by {| u | u.display_rank o 99999} 'funcionó y pone los nils al último. usar o 0 los pondría primero. – Dan

3

Bueno, sólo Post.find(:all) podría devolver una matriz de objetos de AR. Por lo tanto, podría usar Array.sort_by y pasarle un bloque, y dado que esos registros ya se obtuvieron, puede acceder al atributo virtual dentro del bloque que sort_by toma.

RDoc: Enumerable.sort_by

15

Sólo para ampliar @ respuesta de Robbie

Post.all.sort_by {|post| post.custom_method }.reverse 
+0

Ten cuidado si va a haber muchas publicaciones. Sacarlos todos del DB y cargarlos en objetos ActiveRecord no es gratis. Cuando el número de registros se vuelve grande, la disminución será importante para una aplicación de producción. Un campo que está realmente en su base de datos, con un índice apropiado, y que limita la consulta a un conjunto paginado es el camino a seguir. – jwarchol

+0

Paginación, sí, concedida. Pero el índice adecuado es insignificante porque mi método personalizado produce una clasificación basada en el tiempo. Lo cual siempre está cambiando. Por lo tanto, los resultados pueden cambiar instantáneamente. – Trip

+0

He trabajado un poco con los sistemas de clasificación. Pueden ser difíciles de hacer en tiempo real para grandes conjuntos de registros cuando el cálculo no es trivial. La mejor de las suertes, si encuentra alguna técnica útil, comparta :-) – jwarchol

-5

en los carriles 3 podemos hacer esto como: Post.order("custom_method DESC")
Al actualizar la aplicación de rails2 a rails3

+0

Esto no es exacto. – jeffdill2

6

Como se ha señalado la primera respuesta, el orden es una El comando Active Record que básicamente hace una consulta SQL en su base de datos, pero ese campo realmente no existe en su base de datos.

Como alguien comentó, puede ejecutar de forma más limpia el método de Ruby sort_by utilizando el signo (+ info here):

Post.all.sort_by(&:custom_method)

Sin embargo, las cosas se ponen complicadas dependiendo de lo que quiere hacer en tu opinión. Compartiré un caso que hice recientemente en caso de que lo ayude a pensar en su problema. Necesitaba agrupar mi recurso por otro recurso llamado "categorías", y luego ordenar el recurso original por "netvotes", que era un método de modelo personalizado, luego ordenar por nombre. Lo hice por:

  • de pedido por su nombre en el controlador: @resources = Resource.order(:name)
  • Agrupar por categoría en el bucle exterior de la vista: <% @resources.group_by(&:category).each do |category, resources| %>
  • Entonces la clasificación de los recursos por votos en el parcial para recursos: <%= render resources.sort_by(&:netvotes).reverse %>

la vista es un poco confuso, por lo que aquí es la vista vuelta completa en index.html.erb:

<% @resources.group_by(&:category).each do |category, resources| %> 
    <div class="well"> 
    <h3 class="brand-text"><%= category.name %></h3> 
    <%= render resources.sort_by(&:netvotes).reverse %> 
    </div> 
<% end %> 

Y aquí está el _resource.html.erb parcial:

<div class="row resource"> 
    <div class="col-sm-2 text-center"> 
    <div class="vote-box"> 
     <%= link_to fa_icon('chevron-up lg'), upvote_resource_path(resource), method: :put %><br> 
     <%= resource.netvotes %><br> 
     <%= link_to fa_icon('chevron-down lg'), downvote_resource_path(resource), method: :put %> 
    </div> 
    </div> 
    <div class="col-sm-10"> 
    <%= link_to resource.name, resource.link, target: "_blank" %> 
    <p><%= resource.notes %></p> 
    </div> 
</div> 
2

Esto es un poco más complicado que lo que me gusta, pero esto me gusta mantener mi clase para permanecer como un modelo de registro activo por lo que su poco más complicado que simplemente

Post.all.sort_by {|post| post.custom_method } 

lo lo que hago es:

ids = Post.all.sort_by {|post| post.custom_method }.map(&:ids) 
Post.for_ids_with_order(ids) 

este es un ámbito personalizado en el modelo post

#app/models/post.rb 
class Post < ApplicationRecord 
    ... 
    scope :for_ids_with_order, ->(ids) { 
    order = sanitize_sql_array(
     ["position(id::text in ?)", ids.join(',')] 
    ) 
    where(:id => ids).order(order) 
    } 

    ... 
end 

Espero que esta ayuda

Cuestiones relacionadas