如何将其转换为has_one关联?
(可能has_one +大小的命名范围。)
class User < ActiveRecord::Base
has_many :assets, :foreign_key => 'creator_id'
def avatar_asset size = :thumb
# The LIKE is because it might be a .jpg, .png, or .gif.
# More efficient methods that can handle that are OK. ;)
self.assets.find :first, :conditions =>
["thumbnail = '#{size}' and filename LIKE ?", self.login + "_#{size}.%"]
end
end
编辑:来自Freenode #rubyonrails的AnalogHole的Cuing,我们可以这样做:
has_many :assets, :foreign_key => 'creator_id' do
def avatar size = :thumb
find :first, :conditions => ["thumbnail = ? and filename LIKE ?",
size.to_s, proxy_owner.login + "_#{size}.%"]
end
end
...这是相当酷的,至少使语法更好。
但是,这仍然不如我想的那么好。特别是,它不允许更好的查找链接(这样它就不会执行此查找,直到它获得所有条件)。
更重要的是,它不允许在:include中使用。理想情况下,我想做这样的事情:
PostsController
def show
post = Post.get_cache(params[:id]) {
Post.find(params[:id],
:include => {:comments => {:users => {:avatar_asset => :thumb}} }
...
end
...以便我可以将资产与帖子一起缓存。或者根本就缓存它们 - 例如get_cache(user_id){User.find(user_id, :include => :avatar_assets)}
将是一个良好的第一关。
这实际上不起作用(self == User),但在精神上是正确的:
has_many :avatar_assets, :foreign_key => 'creator_id',
:class_name => 'Asset', :conditions => ["filename LIKE ?", self.login + "_%"]
(也发布在Refactor My Code。)
答案 0 :(得分:0)
由于实际上有多个avatar_assets
(每个大小一个),因此您必须将其保留为has_many
关联。
class User < AR::B
has_many :avatar_assets, :conditions => ['filename like ?' '%avatar%'], :class_name => 'Asset'
named_scope :avatar_size, lambda { |size|
{ :conditions => [ "thumbnail = ?", size ] }
}
end
另一种方法是将所有工作放在命名范围内:
class User < AR::B
named_scope :avatar_for, lambda { |user, options|
if options[:size]
{ :conditions => [ "filename like ? AND thumbnail = ?", user.login, options[:size] ] }
else
{ :conditions => [ "filename like ?", user.login ] }
end
}
end
这允许你说
Asset.avatar_for(current_user, :size => :medium)
但是当你发现自己说
时就不那么酷了current_user.avatar_for( current_user, :size => :medium )
您可以向用户添加一些:avatar
,:avatar?
等方法来清理它。
就个人而言,我建议您查看Paperclip插件并完全避免这些问题。
修改强>
根据你的评论,要创建一个条件,例如“通过具有头像的用户向我显示评论”,我不确定是否会这样做。你可以这样建立一种关系:
class Comment
named_scope :with_avatars, :include => { :user => :avatar_assets }, :conditions => [ 'assets.thumbnail = ?', :thumb ]
end
修改强>
由于您只对缓存感兴趣,而不是条件,我们可以删除条件数组:
named_scope :with_avatars, :include => { :user => :avatar_assets }
我修改了上面的代码以使其更加可行。关键的区别在于使资产的“化身”易于查询。如果您可以将现有的avatar_assets更新为包含模式'avatar- [login]'的文件名,则可以将条件设置为静态,这比根据用户登录搜索头像要清晰得多。关联扩展是解决此问题的另一种方法,但我认为您不能将它们链接起来或将它们与命名范围结合起来。