我有一个问题模型,可以从(@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
我在这里做错了什么?
答案 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语句