我将从描述我的联想开始。我有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上的完整应用程序,仅用于上下文。
答案 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
我从这次体验中获得的最重要的事情就是把这样的大问题分解成可管理的小块。为此,我们说:
再次感谢IRC中的jstrong和所有帮助过的人。