Как вы заказываете пользовательский метод модели, который не имеет атрибута в SQL? - PullRequest
29 голосов
/ 30 октября 2010

Ранее я заказывал свои посты так:

@posts = Post.find(:all, :order => "created_at DESC")

Но теперь я хочу заменить created_at на собственный метод, который я написал в модели Post, который в качестве результата дает число.

Мое предположение:

@posts = Post.find(:all, :order => "custom_method DESC")

, что не удается ..

Ответы [ 6 ]

34 голосов
/ 30 октября 2010

Сбой, потому что вы просите свою БД выполнить сортировку.

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

Обратите внимание, что это становится нетривиальным, если вы хотите начать пейджинг результатов и больше не хотите получать .all. Подумайте немного о своем дизайне, прежде чем приступить к этому.

15 голосов
/ 30 октября 2010

Просто чтобы расширить @ ответ Робби

Post.all.sort_by {|post| post.custom_method }.reverse
9 голосов
/ 17 сентября 2015

Как отмечалось в первом ответе, order - это команда Active Record, которая, по сути, выполняет SQL-запрос к вашей базе данных, но это поле фактически не существует в вашей базе данных.

Как прокомментировал кто-то другой, вы можете более аккуратно запустить метод Ruby sort_by, используя амперсанд (подробнее здесь ):

Post.all.sort_by(&:custom_method)

Однако все усложняется в зависимости от того, что вы хотите сделать по вашему мнению. Я поделюсь делом, которое я недавно сделал, чтобы помочь вам обдумать вашу проблему. Мне нужно было сгруппировать свой ресурс по другому ресурсу, называемому «категориями», а затем отсортировать исходный ресурс по «netvotes», который представлял собой метод пользовательской модели, а затем упорядочить по имени. Я сделал это:

  • Порядок по имени в контроллере: @resources = Resource.order(:name)
  • Группировка по категориям во внешнем цикле представления: <% @resources.group_by(&:category).each do |category, resources| %>
  • Затем сортировка ресурсов по голосам в частичном для ресурсов: <%= render resources.sort_by(&:netvotes).reverse %>

Представление немного сбивает с толку, поэтому вот полный цикл просмотра в 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 %>

А вот часть _resource.html.erb:

<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>
3 голосов
/ 30 октября 2010

Ну, просто Post.find(:all) вернет массив объектов AR.Таким образом, вы можете использовать Array.sort_by и передать ему блок, а поскольку эти записи уже получены, вы можете получить доступ к виртуальному атрибуту внутри блока, который принимает sort_by.*

2 голосов
/ 05 июня 2017

Это немного сложнее, чем мне нравится, но я предпочитаю, чтобы мой тип оставался активной моделью записи, поэтому он немного сложнее, чем

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

что я делаю, это:

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

это пользовательская область в модели 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

Я надеюсь, что это поможет

0 голосов
/ 28 марта 2014

в рельсах 3 мы можем сделать это как: Post.order("custom_method DESC")
При обновлении приложения с rails2 на rails3

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...