我有一个游戏模型has_many:文本。问题是我必须根据他们所属的游戏来区分不同的文本(是的,丑陋的,但它是遗留数据)。我创建了一个Text.in_game_order_query(game)
方法,它返回了相应的顺序。
我最喜欢的解决方案是在Text模型中放置一个默认范围,但这需要知道它们属于哪个游戏。我也不想为每个游戏的文本创建单独的类 - 有很多游戏,有更多的游戏,所有较新的游戏将使用相同的顺序。所以我有另一个想法:在has_many中订购文本,当我知道它们属于哪个游戏时:
has_many :texts, :order => Text.in_game_order_query(self)
然而,自我就是这里的阶级,所以这不起作用。
除了每次调用@game.texts.in_game_order(@game)
之外,真的没有其他解决方案吗?
答案 0 :(得分:5)
我最近遇到了一个非常类似的问题,我确信在Rails中它是不可能的,但我学到了很多有趣的东西。
您可以为范围声明一个参数,然后不将其传入,默认情况下它将传递给父对象!
所以,你可以这样做:
class Game < ActiveRecord
has_many :texts, -> (game) { Text.in_game_order_query(game) }
信不信由你,你不必通过游戏。 Rails会为你神奇地做。你可以这样做:
game.texts
但有一点需要注意。如果您启用了预加载,这在目前的Rails中将不起作用。如果您这样做,您可能会收到此警告:
弃权警告:关联范围&#39;文本&#39;是实例相关的(范围块采用参数)。预加载在创建单个实例之前发生。这意味着没有实例传递给关联范围。这很可能导致行为破裂或不正确。这些关联的加入,预加载和急切加载已弃用,将来将被删除。
答案 1 :(得分:3)
继续使用PradeepKumar的想法后,我找到了以下解决方案
假设一个类Block
有一个属性block_type
和一个容器类(比如Page),你可以这样:
class Page
...
has_many :blocks do
def ordered_by_type
# self is the array of blocks
self.sort_by(&:block_type)
end
end
...
end
然后当你打电话
page.blocks.ordered_by_type
你得到你想要的东西 - 由Proc定义。 显然,Proc可能要复杂得多,并且在SQL调用中没有工作,但是在编译结果集之后。
更新:
经过一段时间后,我重新阅读了这篇文章和我的回答,我想知道你是否可以做一些简单的事情,就像你基本上在帖子中提出的另一种方法一样。
如果您向名为Game
ordered_texts
添加了一种方法,该怎么办?
def ordered_texts
texts.in_game_order(self)
end
这是否解决了这个问题?或者这个方法是否需要与其他Game
关系方法链接?
答案 2 :(得分:1)
Association extension是否有可能?
似乎你可以做到这一点:
module Legacy
def legacy_game_order
order(proxy_association.owner.custom_texts_order)
end
end
class Game << ActiveRecord::Base
includes Legacy
has_many :texts, :extend => Legacy
def custom_texts_order
# your custom query logic goes here
end
end
这样,给定游戏实例,您应该能够访问实例的自定义查询而无需传递自己:
g = Game.find(123)
g.texts.legacy_game_order
答案 3 :(得分:0)
这是一种可以做到的方法,
has_many :texts, :order => lambda { Text.in_game_order_query(self) }
这是我通常不推荐的另一种方式(但会起作用),
has_many :texts do
def game_order(game)
find(:all, :order => Text.in_game_order_query(game))
end
end
你可以通过
来打电话给他们game.texts.game_order(game)
答案 4 :(得分:0)
我不确定你的订单/查询在in_game_order_query类方法中是什么样的,但我相信你可以这样做
has_many :texts, :finder_sql => proc{Text.in_game_order_query(self)}
只是让你知道我之前从未使用过这个,但如果你告诉我这是否适合你,我将不胜感激。
有关更多文档,请查看http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many:finder_sql
答案 5 :(得分:-1)
我认为如果你想要处理运行时信息,你应该完成这个:
has_many :texts, :order => proc{ {Text.in_game_order_query(self)} }