2009-06-06 13 views
0

Comment transformer cette méthode en une association has_one?Modifier une méthode find avec w/parameters pour une association

(Peut-être has_one + portée du nom de taille.)

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 

EDIT: Cuing de AnalogHole sur #rubyonrails Freenode, nous pouvons le faire:

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 

... ce qui est assez cool, et rend la syntaxe un peu mieux au moins.

Cependant, cela ne se comporte toujours pas aussi bien que je le voudrais. En particulier, il ne permet pas d'autres chaînages de recherche (de telle sorte qu'il n'exécute pas cette recherche tant qu'il n'a pas toutes ses conditions).

Plus important encore, il ne permet pas l'utilisation dans un: include. Idéalement, je veux faire quelque chose comme ceci:

PostsController 
def show 
    post = Post.get_cache(params[:id]) { 
    Post.find(params[:id], 
     :include => {:comments => {:users => {:avatar_asset => :thumb}} } 
    ... 
end 

... de sorte que je puisse mettre les actifs en cache avec la publication. Ou cachez-les du tout, vraiment - par exemple. get_cache(user_id){User.find(user_id, :include => :avatar_assets)} serait un bon premier passage.

Cela ne fonctionne pas vraiment (auto == utilisateur), mais il est correct dans l'esprit:

has_many :avatar_assets, :foreign_key => 'creator_id', 
:class_name => 'Asset', :conditions => ["filename LIKE ?", self.login + "_%"] 

(. Également publié sur Refactor My Code)

Répondre

0

Comme il y a en fait plusieurs avatar_assets (un pour chaque taille), vous devez le conserver en tant qu'association 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 

Une alternative serait de mettre tous les travaux dans le cadre nommé:

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 

ce qui vous permet de dire

Asset.avatar_for(current_user, :size => :medium) 

mais est moins cool quand vous vous dites

current_user.avatar_for(current_user, :size => :medium) 

vous pouvez ajouter quelques méthodes :avatar, :avatar?, etc à l'utilisateur pour nettoyer cela.

Personnellement, je vous conseille de vérifier le plugin Paperclip et d'éviter ces problèmes entièrement.

EDIT:

par votre commentaire, pour créer une condition comme « Montrez-moi des commentaires par les utilisateurs avatar ayant », je ne suis pas sûr qui le fera.Vous auriez pu faire une relation comme ceci:

class Comment 
    named_scope :with_avatars, :include => { :user => :avatar_assets }, :conditions => [ 'assets.thumbnail = ?', :thumb ] 

end 

EDIT:

Puisque vous n'êtes intéressé que par la mise en cache, plutôt que des conditions, nous pouvons laisser tomber le tableau de conditions:

named_scope :with_avatars, :include => { :user => :avatar_assets } 

J'ai révisé le code ci-dessus pour être plus pratique. La principale différence est de rendre l''avatar' des ressources facilement interrogeable. Si vous pouvez mettre à jour vos avatar_assets existants pour avoir un nom de fichier incluant le motif 'avatar- [login]', vous pouvez rendre le jeu de conditions statique beaucoup plus propre que de devoir toujours chercher l'avatar basé sur la connexion de l'utilisateur. Les extensions d'association sont une autre façon de résoudre ce problème, mais je ne pense pas que vous serez en mesure de les enchaîner ou de les combiner avec des portées nommées.

+0

J'ai effectivement jeté un coup d'oeil à Paperclip; il manque certaines des fonctionnalités les plus sophistiquées dont j'ai besoin. (Les actifs sont utilisés de façon non triviale dans mon application dans de nombreux endroits et parfois polymorphiquement, avoir un psuedocolumn par type d'actif serait mauvais.) – Sai

+0

Aussi - est-il possible de faire quelque chose comme: Post.find (1) .comments (: include => {: users => {: avatar_asset =>: thumb}})? – Sai

+0

... aussi, AFAICT votre code ne fonctionne pas. Même en ajoutant le nécessaire: class_name et: foreign_key, votre avatar_assets affiche: 'Unknown column 'users.asset_id''' car il ne sait pas sur quel utilisateur il se trouve. Mais je pense que cela m'amène à quelque chose de mieux; devra relire les extensions d'association. – Sai

Questions connexes