0

如何将其变成 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 提示,我们可以这样做:

  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 + "_%"]

(也发布在重构我的代码。)

4

1 回答 1

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 )

您可以向 User 添加一些:avatar, :avatar?, 等方法来清理它。

我个人建议您查看回形针插件并完全避免这些问题。

编辑:

根据您的评论,要创建一个条件,例如“向我展示拥有头像的用户的评论”,我不确定是否会这样做。你可以建立这样的关系:

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]”的文件名,则可以使条件集静态化,这比始终必须根据用户登录来搜索化身要干净得多。关联扩展是解决此问题的另一种方法,但是我认为您无法将它们链接起来或将它们与命名范围结合起来。

于 2009-06-06T23:31:50.320 回答