我已经覆盖了find
的方法ActiveRecord::Base
,这很顺利,现在我可以很好地自定义它。
def self.find(*args)
# my custom actions
super(*args)
end
然后
Album.find(1) #=> My custom result
但现在我想覆盖这个:
Album.first.photos
并且我不确定我应该覆盖哪种方法来完成工作...... 我正在考虑专门针对关联查询的内容,但我不确定:(
我需要对“ActiveRecord :: Base”采取行动,建议使用动态类,因此我无法为此创建方法photos
,而是在我尝试的所有模型中进行交互的方法。
非常感谢
为了更好地解释我想要实现的目标:
创建一个可插入的ruby gem用于rails并且gem可以简单地从数据库中获取ID结构并将其动态转换为缩短ID,就像bit.ly系统一样。但这是动态完成的,只向您的模型声明has_shortened :id
,然后所有界面和查询返回例如DH3
而不是12
,例如,我已设法获得这就是我需要处理关联的问题。
关注宝石网址http://github.com/ludicco/shortener,以便您可以查看它,如果您认为这是一个不错的主意,请随时提出您可能需要实施的建议。
干杯
答案 0 :(得分:2)
您在has_many
定义的关联访问器在场景后面的ActiveRecord中非常复杂。它们实际上使用反射类来返回行为类似于模型类的代理对象,但将其查找器限制为外键(可能还有其他条件)。如果您想深入了解它,您可能需要查看ActiveRecord gem中的reflection.rb,associations.rb,associations / association_proxy.rb和associations / association_collection.rb。
但是,最后,我们可以使用关联访问器,就好像它本身就是类本身一样,ActiveRecord会将所需的附加条件传递给类查找器。
这意味着,如果您在场景后面调用Album.first.photos
,则ActiveRecord会调用Photo.find
(附加条件仅返回具有以下内容的记录:album_id => Album.first.id)。 / p>
因此,如果您覆盖Photo.find
,如果您通过Album.first.photos
使用它,它也会返回您修改后的结果。那是ActiveRecord魔术:)
我的快速测试(使用Rails 2.3.8运行):
class Album < ActiveRecord::Base
has_many :photos
end
class Photo < ActiveRecord::Base
belongs_to :album
def self.find (*args)
puts "XXX running custom finder"
super
end
end
Rails控制台:
> Photo.all
XXX running custom finder
Photo Load (0.4ms) SELECT * FROM "photos"
=> [#<Photo id: 1, album_id: 1>, … ]
> Album.first.photos
Album Load (0.4ms) SELECT * FROM "albums" LIMIT 1
XXX running custom finder
Photo Load (0.3ms) SELECT * FROM "photos" WHERE ("photos".album_id = 1)
=> [#<Photo id: 1, album_id: 1>, … ]
答案 1 :(得分:1)
由于Album.first
会返回相册的实例,您应该覆盖photos
类本身的Album
方法:
class Album < ActiveRecord::Base
# ...
def photos(*args)
if my_condition_is_met
// my custom handler
else
super
end
end
# ...
end
现在,如果您确定每个模型实例都需要这个,我宁愿将它隔离在模块上:
module Photo
def photos(*args)
if my_condition_is_met
// my custom handler
else
super
end
end
end
重新打开ActiveRecord::Base
课程:
class ActiveRecord::Base
include Photo
end
通过这种方式,您可以获得解决方案的模块化,使其成为“插件”。
一个额外且不相关的注意事项:您不必致电super(*args)
,因为只调用super
会传递您收到的所有参数。
编辑:次要格式
答案 2 :(得分:0)
是否有特殊原因使用关联扩展名无法执行此操作?
http://ryandaigle.com/articles/2006/12/3/extend-your-activerecord-association-methods
直接与代理对象混淆是要求麻烦。但是,如果您只想覆盖查找,则可能会这样做。
答案 3 :(得分:0)
看看friendly_id插件(http://github.com/norman/friendly_id http://norman.github.com/friendly_id/file.Guide.html),它可以满足您的需求:为模型生成自定义ID别名。您可以定义自定义方法来生成slug。
在模型
中保留 id 字段对于自定义#find使用:finder_sql选项:
class Album < ActiveRecord::Base
has_friendly_id :short_id
has_many :photos, :finder_sql => 'select * from photos where album_id="#{short_id}"'
end
>> Album.last.photos
select * from photos where album_id="t54"