来自协会的排名最高的项目

时间:2013-11-22 17:52:39

标签: ruby-on-rails ruby ruby-on-rails-4 rails-activerecord

我将从描述我的联想开始。我有6个资源。 NationalOffice,Program,Village,Discussion,Conversation,and Change。 NationalOffice 有许多程序计划有许多村庄 Village 有很多讨论讨论有许多对话会话有一个(belongs_to)a 更改

在每次对话中,都会讨论更改会话然后为更改提供排名。这是表模式:

create_table "conversations", force: true do |t|
  t.integer  "discussion_id"
  t.integer  "change_id"
  t.integer  "rank" # 1 for 1st, 2 for 2nd, 3 for 3rd, ect.
end

我想要做的是以下内容:从讨论课程中,我希望能够选择最重要的变化。我粗略地用帮助器实现了这个:

  def top_change discussion
    conversation = discussion.conversations.order(:rank).first
  # Incase there are no conversations for the discussion
    if conversation.respond_to?('change')
      conversation.change.name 
    else
      'N/A'
    end
  end

如果我把这个级别提升到 Village 课程,我就会遇到问题。我将如何浏览 Village 中的所有讨论并找到最高得分更改?在 Program 类上尝试时,我也会遇到同样的问题。然后是 NationalOffice 类。

这可以通过SQL或activerecord实现 - 我不确定。

我希望自己清楚明白 - 我有时会有清晰的问题。


编辑:

很明显,我没有正确解释排名。我现在将尝试解释它们是如何工作的:

每个对话都有排名。每个对话都与特定的更改有关。因此,如果关于更改 1的对话讨论中排名第一* *更改* 1将获得第一名。在另一个讨论中,关于更改的对话 1排名第2。那么改变 1现在有1和2(3分?)。

2 讨论每个人都有一个对话,谈论变更 2.一个排名第一,另一个排名第三。 更改 2有第1和第3(4分?)

总而言之,变更 1是最重要的变化 - 它比变更 2获得更少的分数(更高的得分)。

希望这很清楚。 This是github上的完整应用程序,仅用于上下文。

2 个答案:

答案 0 :(得分:0)

您可以使用has_many:through来实现此目的。

http://ryandeussing.com/blog/2013/06/12/nested-associations-and-has-many-through/

Has_many将添加额外的条件以在3个或更多表之间进行连接。所以你应该可以在“对话”之上的所有类中使用它。

基本上你可以链接has_many:通过你需要的次数来找到任何相关模型的顶级对话。

在你的模特中:

class Discussion < AR::Base
  belongs_to :village
  has_many :conversations
end

class Conversation < AR::Base
  belongs_to :discussion
  has_one :change
end

class Village < AR::Base
  has_many :discussions
  has_many :conversations, through: :discussions
end

class Programme < AR::Base
  has_many :villages
  has_many :conversations, though: :villages
end

在您的控制器中:

class VillageController < ApplicationController
  def top_change
    village = Village.find(params[:id])
    @change = village.conversations.order(:rank).first.change
  end
end

class ProgrammesController < ApplicationController
  def top_change
    programme = Programme.find(params[:id])
    @change   = programme.conversations.order(:rank).first.change
  end      
end

答案 1 :(得分:0)

我最终在freenode irc网络的#rubyonrails频道中与James Strong一起解决了问题。这是我们得到的:

在更改模型中,我们添加了两个操作:

def self.with_rank(load_conversation=true)
  q = select("changes.*, SUM(11 - conversations.rank) as score").group("changes.id")
  q = q.joins(:conversations) if load_conversation
  return q
end

这经历了与变更相关的所有对话,然后对所有等级进行了调整(但是我们做得越高越好。如果等级是1:1 - 11 = 10,则将IE放入表中) as * conversations_rank *。然后它将更改表与会话表连接起来。

def self.top_ranked(load_conversation=true)
  with_rank(load_conversation).order("score desc").limit(1)
end

下一个小片段会返回排名靠前的变化。这是非常自我解释的。

在Villages模型中,我们添加了一个动作,将top_rank查询与该模型的更改(Villages.changes)合并。

def top_change
  changes.merge Change.top_ranked(false)
end

它还有以下关联:

has_many :conversations, through: :discussions

这使我可以执行以下操作以获取最高更改的名称:

@village.top_change.name

我从这次体验中获得的最重要的事情就是把这样的大问题分解成可管理的小块。为此,我们说:

  1. 根据转化次数(合并得分)获得排名变更
  2. 获得最高排名
  3. 获得村内最高排名
  4. 再次感谢IRC中的jstrong和所有帮助过的人。