Rails-使用订单对模型进行排序

时间:2018-11-30 22:02:57

标签: ruby-on-rails

我有一个问题模型,可以从(@rejected)中选择项目。然后,我想为每个项目计算一个:approval_rating属性,并根据该属性对集合进行排序。我正在尝试使用以下方法:

def index
  ...
  @rejected = @questions.where("ques_num=? AND rejected=?", params[:ques_num], true) 
    if @rejected   
      @rejected = @rejected.map do |q|
        upvotes = q.get_upvotes.size
        downvotes = q.get_downvotes.size
        total_votes = Float(upvotes + downvotes)
        q.approval_rating = (upvotes/total_votes*100).round(2)
        q.save
      end
      @rejected = @rejected.order('approval_rating DESC')
    end
  end

这在尝试排序时给我错误: [true,true,true]:Array

的未定义方法`order'

我也尝试过

@rejected = @rejected.sort_by(&:approval_ratings)

并得到错误:未定义方法'approval_rating'为true:TrueClass

我在这里做错了什么?

2 个答案:

答案 0 :(得分:2)

您的代码创建值为Array的{​​{1}}(见下文)

true

并且def index ... @rejected = @questions.where("ques_num=? AND rejected=?", params[:ques_num], true) if @rejected @rejected = @rejected.map do |q| upvotes = q.get_upvotes.size downvotes = q.get_downvotes.size total_votes = Float(upvotes + downvotes) q.approval_rating = (upvotes/total_votes*100).round(2) q.save # <= this is what gets added to the array from map, which is 'true' end @rejected = @rejected.order('approval_rating DESC') end end true:TrueClass没有响应。

您的代码还有其他一些问题。这个:

approval_rating

将始终返回@questions.where("ques_num=? AND rejected=?", params[:ques_num], true) ,因此:

ActiveRecord::Relation

将始终返回true。

您可能想考虑使用if @rejected 而不是each。但是,我相信那仍然会返回map。因此,您仍然无法执行Array

认为,您应该可以做到:

@rejected.order('approval_rating DESC')

我不确定100%会确定您的排序顺序是否正确,因此您可能需要检查一下。

就我个人而言,似乎最好将def index ... @rejected = @questions. where("ques_num=? AND rejected=?", params[:ques_num], true). each do |q| upvotes = q.get_upvotes.size downvotes = q.get_downvotes.size total_votes = Float(upvotes + downvotes) q.approval_rating.update( approval_rating: (upvotes/total_votes*100).round(2) ) end. sort_by(&:approval_rating) end 逻辑放入approval_rating模型中。也许像这样:

Question

在这种情况下,您可以

class Question < ApplicationRecord

  def update_approval_rating
    upvotes     = get_upvotes.size
    downvotes   = get_downvote.size
    total_votes = Float(upvotes+downvotes)
    update(
      approval_rating: (upvotes/total_votes*100).round(2)
    )
  end

end

在我看来,您可能考虑每次def index ... @rejected = @questions. where("ques_num=? AND rejected=?", params[:ques_num], true). each{|q| q.update_approval_rating}. sort_by(&:approval_rating) end 投票(大概在您的approval_rating中)设置Question。这样,您就不必在QuestionsController操作中设置approval_rating了。此外,index应该是幂等的,因此在那里修改记录似乎很臭(IMO)。

然后,您可能会得到类似以下的内容:

index

啊...好多了。

您甚至可以在def index ... @rejected = @questions. where("ques_num=? AND rejected=?", params[:ques_num], true). order(approval_rating: :desc) end 模型上添加一些类方法,例如:

Question

在这种情况下,您可以这样做:

class Question < ApplicationRecord
  class << self 

    def for_question_number(ques_num)
      where(ques_num: ques_num)
    end 

    def rejected
      where(rejected: true)
    end

    def best_first
      order(approval_rating: :desc)
    end

  end
end

如果将来您决定以某种其他方式确定“最佳”方法,则可以在def index ... @rejected = @questions. for_question_number(params[:ques_num]). rejected. best_first end 模型和{{1}中对best_first方法进行更改}采取行动是不明智的。

现在这里开始像彩虹和棒棒糖一样。

答案 1 :(得分:0)

您正在使用map返回一个数组。如果要应用order之类的AR查询方法,则需要提供ActiveRecord::Relation类。这里最简单的解决方案-执行另一个查询以基于修改后的字段对关系进行排序,或者使用@rejected用ruby对sort_by进行排序。

def index
  ...
  @rejected = @questions.where("ques_num=? AND rejected=?", params[:ques_num], true) 
  if @rejected.present?   
     @rejected.each do |q|
        upvotes = q.get_upvotes.size
        downvotes = q.get_downvotes.size
        total_votes = Float(upvotes + downvotes)
        q.approval_rating = (upvotes/total_votes*100).round(2)
        q.save
      end
      @rejected = @questions.where("ques_num=? AND rejected=?", params[:ques_num], true).order('approval_rating DESC')
    end
  end
end

注意:您的@rejected始终== true(空关系[]视为true)。使用@rejected.present?

也许最好将迭代器中的代码写入SQL / AR语句