我已经覆盖了 ActiveRecord::Base
的 find
方法,效果非常好,现在我可以很好地自定义它。
def self.find(*args)
# my custom actions
super(*args)
end
然后
Album.find(1) #=> My custom result
但是现在我想重写这个:
Album.first.photos
并且我不确定我到底应该重写什么方法来完成工作......
我正在考虑一些专门用于关联查询的方法,但我不确定:(
我需要对建议动态类的“ActiveRecord::Base”采取行动,这样我就无法创建方法photos
那,但是一种可以在我尝试的所有模型中进行交互的方法,
非常感谢
更新,
以便更好地解释我想要实现的目标:
创建一个与 Rails 一起使用的可插入 ruby gem,并且该 gem 可以简单地获取 ID 结构。从数据库中将其即时转换为缩短的 ID,就像 bit.ly 系统一样。仅向您的模型声明 has_shortened :id
即可飞行,然后所有接口和查询都会返回例如 DH3
而不是 12
例如,我已经设法让这个工作了,我需要处理关联。
遵循 gem url http://github .com/ludicco/shortener,这样您就可以查看它,如果您认为这是一个好主意,请随时提出您可能需要实现它的想法。
干杯
I've overrode the method find
for ActiveRecord::Base
and that went pretty well, now I can customize it nicely.
def self.find(*args)
# my custom actions
super(*args)
end
then
Album.find(1) #=> My custom result
But now I would like to override this:
Album.first.photos
and I'm not sure what method exactly I should override to get the job done...
I'm thinking of something specifically for associative queries, but I'm not sure :(
I need to act on 'ActiveRecord::Base' suggesting dynamic classes so I couldn't create a method photos
for that, but a method that will interact within all the models I try.
Thanks a lot
Update
For better explaining what I'm trying to achieve:
Is to create a pluggable ruby gem for use with rails and that gem can simply take you ID structure from the database and convert it on the fly to a shorten ID just like bit.ly system. but this is done on the fly with only declaring has_shortened :id
to your model, and then all the interface and queries return for example DH3
instead of 12
for example, I've managed to get this working this the point I need to deal with associataions.
Follow the gem url http://github.com/ludicco/shortener so you can check it out, and feel free to come with ideas you might have to implement it if you think it's a nice idea.
Cheers
发布评论
评论(4)
像您使用
has_many
定义的关联访问器在 ActiveRecord 中是非常复杂的东西。他们实际上使用反射类返回一个行为类似于模型类的代理对象,但将其查找器限制为外键(可能还有其他条件)。如果您想更深入地了解它,您可能需要查看 ActiveRecord gem 中的 Reflection.rb、association.rb、association/association_proxy.rb 和 Associations/association_collection.rb。然而,最终,我们可以使用关联访问器,就像它是类本身一样,并且 ActiveRecord 会小心地将所需的附加条件传递给类查找器。
这意味着,如果您在幕后调用
Album.first.photos
,ActiveRecord 会调用Photo.find
(附加条件是仅返回具有 :album_id => 的记录专辑.first.id)。因此,如果您重写
Photo.find
,并且通过Album.first.photos
使用它,它也会返回修改后的结果。这就是 ActiveRecord 的魔力 :)我的快速测试(使用 Rails 2.3.8 运行):
Rails 控制台:
Association accessors like you define with
has_many
are pretty complicated stuff in ActiveRecord behind the scene. They actually use a reflection class to return a proxy object that behaves like a model class, but restrict its finders to the foreign key (and maybe other conditions). If you like to get deeper into it, you might want to have a look at reflection.rb, associations.rb, associations/association_proxy.rb and associations/association_collection.rb in the ActiveRecord gem.However, in the end, we can use an association accessor as if it would be the class itself and ActiveRecord takes care to pass the required additional conditions to the class finder.
That means, that if you call
Album.first.photos
, behind the scene, ActiveRecord callsPhoto.find
(with additional condition to only return records that have :album_id => Album.first.id).So, if you override
Photo.find
, it'll return your modified results as well if you use it throughAlbum.first.photos
. That's ActiveRecord magic :)My quick test (ran with Rails 2.3.8):
Rails console:
由于
Album.first
返回 Album 的实例,因此您应该重写Album
类本身的photos
方法:现在,如果您确定需要对于每个模型实例,我宁愿将其隔离在一个模块上:
并重新打开
ActiveRecord::Base
类:这样您的解决方案就会模块化,使其充当“插件”。
一个额外且不相关的注释:您不必调用
super(*args)
,因为仅调用super
将传递所有您收到的参数。编辑:小格式
Since
Album.first
returns an instance of Album, you should override thephotos
method on theAlbum
class itself:Now if you are sure you need this for every single model instance, I'd rather isolate it on a module:
And reopen
ActiveRecord::Base
class:This way you get modularization for your solution, making it act like a "plugin".
One additional and unrelated note: you don't have to call
super(*args)
, since a call to onlysuper
will pass along all the parameters you received.EDIT: Minor formatting
看看Friendly_id插件(http://github.com/norman/Friendly_id http://norman.github.com/Friendly_id/file.Guide.html),它执行您需要的操作:为模型生成自定义 id 别名。您可以定义自定义方法来生成 slug。
在模型中保留 id 字段
对于自定义 #find 使用 :finder_sql 选项:
Take a look at friendly_id plugin (http://github.com/norman/friendly_id http://norman.github.com/friendly_id/file.Guide.html), it does what you need: generate custom id alias for model. You can define custom method to generate slug.
Leave id field in model
For custom #find use :finder_sql option:
是否有特殊原因无法使用关联扩展来执行此操作?
http://ryandaigle.com/articles/2006/ 12/3/extend-your-activerecord-association-methods
直接修改代理对象是自找麻烦。但如果你只是想覆盖查找结果,这可能可以做到。
Is there an particular reason you can't do this with an association extension?
http://ryandaigle.com/articles/2006/12/3/extend-your-activerecord-association-methods
Messing with the proxy objects directly is asking for trouble. But if you just want to override the find, this might do it.