2010-04-22 19 views
5

problèmes avec AR 2.3.5, par exemple:Comment forcer le type d'attribut ActiveRecord renvoyé par: select phrase sur la table jointe?

users = User.all(:select => "u.id, c.user_id", :from => "users u, connections c", 
     :conditions => ...) 

retours, par exemple:

=> [#<User id: 1000>] 
>> users.first.attributes 
=> {"id"=>1000, "user_id"=>"1000"} 

Notez que retourne AR le id du modèle recherché comme numérique, mais sélectionné user_id du modèle joint en tant que String, bien que les deux soient int(11) dans le schéma de base de données.

Comment pourrais-je mieux former ce type de requête pour sélectionner des colonnes de tables sauvegardant plusieurs modèles et récupérer leur type naturel plutôt que String? On dirait que l'AR est en train de piquer quelque part. Comment pourrais-je contraindre les types retournés au moment du chargement de l'AR et ne pas avoir à virer de .to_i (etc.) sur chaque accès post-hoc?

+1

Pouvez-vous expliquer ce que « connexions » est, et comment est-elle liée aux utilisateurs? – kikito

Répondre

1

Pourquoi utilisez-vous: de => "utilisateurs" à l'intérieur d'un utilisateur.Procédé? Ce qui suit fera une jointure (qui est ce que vous faites de toute façon)

users = User.all(:include => :connections, :select => "users.id, connections.user_id", :conditions => {...}) 

Cela va être très lourd requête pour la base de données. requête plus rapide serait avec la jointure externe si.

Cela permettra également remettre les clés INT accumulez pas

Une alternative beaucoup plus rapide était

Connection.all(:include => :user, :conditions => {...}).collect {|e| [e.user_id, e.id] } 

Cela vous donne un tableau de tableaux avec les ids. Si vous sélectionnez uniquement les colonnes "id, id_utilisateur", il se peut qu'il ne soit pas nécessairement un objet AR. Un tableau peut être plus rapide.

J'espère ne pas manquer un point ici. Proposez-moi, si je le suis.

+0

Le: de: a été inclus pour alias les noms des colonnes de la table. Des sous-conditions sont mélangées dynamiquement. Je vais considérer votre approche et faire quelques tests avec elle - merci. – tribalvibes

2

Malheureusement, ça ne va pas se passer très facilement. Toutes les données de la connexion DB arrivent à des rails sous forme de chaînes, la conversion des types se produit dans chacune des méthodes d'attributs dynamiques que les rails créent lors de l'exécution. Il sait quels attributs convertir en quel type par les méta-données de type colonne de la table qu'il récupère au démarrage de l'application. Chaque modèle n'a que des métadonnées de colonne pour ses propres colonnes, c'est pourquoi ses propres colonnes finissent avec le type correct. Il n'y a pas de moyen facile de convertir automatiquement les types corrects.

Vous pouvez, en revanche, créer une méthode de conversion simple qui prendrait un hachage et convertirait automatiquement les attributs.

Quelque chose comme ceci:

users = User.all(:select => "cl, comments.c2", ...) 
users = convert_columns(users, 'c2' => :integer, 'other_column' => :date) 

def convert_columns(records, columns = {}) 
    records.each do |rec| 
    columns.each do |col, type| 
     rec[col] = case type 
     when :int then rec[col].to_i 
     when :date then ........ 
     .... 
     end 
    end 
    end 
end 
0

Si vous voulez une solution rapide - essayez d'utiliser after_find rappel et types attributs corrects prédéfini il:

class User < ActiveRecord::Base 

    after_find :preset_types 


    private 
    def preset_types user 
    user.user_id = user.user_id.to_i 
    end 

end