IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Ruby on Rails Discussion :

Probleme de joins, il ne fait pas la liaison tout seul


Sujet :

Ruby on Rails

  1. #1
    Membre habitué
    Inscrit en
    Février 2004
    Messages
    279
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 279
    Points : 164
    Points
    164
    Par défaut Probleme de joins, il ne fait pas la liaison tout seul
    Salut a tous,

    J'ai plusieurs tables :
    recettes, livres, droits.

    Dans un livre il y a plusieurs recettes et une recette a un droit (public ou private)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Book < ActiveRecord::Base
      belongs_to :user
      has_many :recipes
    end
     
    class Right < ActiveRecord::Base
      has_many :recipes
    end
     
    class Recipe < ActiveRecord::Base
      belongs_to :book
      belongs_to :right
    end
    Les liaisons bien faites, je verifie ma bdd, il existe bien un book.id, un book_id dans la table user, un book_id et un right_id dans la table recipes

    Lorsque je fais ma requete:
    @recipes = Recipe.joins(:rights).select(" id, title, description, photo1, photo2 ,rights.id as right_id").where(:id => params[:id])
    Bah il m'envoit balader

    Association named 'rights' was not found; perhaps you misspelled it?

    Quelqu'un aurait une idee?

    Jai trois autres tables que j'arrive tres bien a liee. Les liaisons sont identiques...
    Je dois manquer quelque chose...
    Merci d'avance
    Sand

  2. #2
    Membre averti Avatar de Gregory.M
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    684
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Novembre 2007
    Messages : 684
    Points : 309
    Points
    309
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    @recipes = Recipe.joins(:rights).select(" id, title, description, photo1, photo2 ,rights.id as right_id").where(:id => params[:id])
    Il ne faut pas de "s" sur ta jointure puisqu'une recette n'a qu'n seul droit. De plus dans ta relation tu l'as également mit sans "s", ce qui est bon.

    A+

  3. #3
    Membre habitué
    Inscrit en
    Février 2004
    Messages
    279
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 279
    Points : 164
    Points
    164
    Par défaut
    Ah mais j'ai essaye avec un S et sans S.

    Desole javais oublie de le specifier.

    Jai deja rencontre ce probleme et c'etait car dans ma bdd mon champ cle etrangere etait nomme avec un s genre roles_id donc je lai renommer role_id
    et yalla il ma trouve ma liaison.

    Mais la tout semble bien ecrit donc je ne comprends pas.
    En attendant de trouver la solution je force le join :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     :joins => " inner join books bk on bk.id = recipes.book_id "
    Mais la je cale, en plus ca doit etre un truc tout simple!
    grrrrr

    Merci encore

  4. #4
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 2
    Points : 2
    Points
    2
    Par défaut
    Bonjour,

    Quel est le résultat escompté ?
    Pourquoi un join ?

    Cette requête est étrange :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @recipes = Recipe.joins(:rights).select(" id, title, description, photo1, photo2 ,rights.id as right_id").where(:id => params[:id])
    elle ne retourne qu'une recette par son id (le where(:id => params[:id]) se rapportant a Recipe) et utilise un join sur rights pour overrider en quelque sorte
    le right_id dans le resultat alors que celui ci est déja présent dans la table recipes car Recipe belongs_to :right.

    Elle revient a faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @reciepes = Recipe.find(params[:id])
    Pour les requêtes complexes mieux vaut deux selects qu'un join pour les perfs.

    par exemple pour une collection de Books d' un utilisateur donné contenant des recette ayant un droit spécifique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @books = @user.books.where(:id => Recipe.where(:right_id => @right.id).map{|recipe| recipe.book_id})
    Ensuite pour des requêtes devant renvoyer des collections et leurs objets liés,
    le eager loading est un bon reflexe avec include() pour ne pas avoir un hammering de la base.

    D'expérience, c'est souvent la meilleur façon de raisonner Sous rails.

  5. #5
    Membre habitué
    Inscrit en
    Février 2004
    Messages
    279
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 279
    Points : 164
    Points
    164
    Par défaut
    Merci beaucoup pour les precisions.

    En effet ma requete n'a pas de sens, c'est juste que j'y allais doucement, je comptais rajouter une nouvelle condition qui renvoyait la recette suivant le droit.

    Je viens de tester les deux selects mais cela ne marche pas
    jai fait quelque chose de tres simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @users_all = @user.book.where(:id => params[:id])
    =>NoMethodError (undefined method `book' for nil:NilClass):

    Jai tente book ou books mais jai eu le meme message d'erreur.

    Jai tente avec une autre table (roles) avec user, ou je sais que cette liaison est faite correctement (car je l'utilise dans mon code) et jai le meme message d'erreur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @users = User.joins(:role, :language).select(" users.id as id, pseudo, email, city, country, role as rol, language as lang").where(:id => params[:id])
    Extra question , est ce que je peux optimiser cette derniere requete?

    Merci beaucoup d'avance
    Bonne journee

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 2
    Points : 2
    Points
    2
    Par défaut
    Bonjour

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @users_all = @user.book.where(:id => params[:id])
    Cette requête fonctionne si et seulement si @user est une instance de la classe User.
    ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @user = User.find(user_id) #où user_id est un id d'utilisateur valide.
    De plus, le pluriel sur book dépend du type de relation.
    si User has_one :book, c'est @user.book
    si User has_many :books, c'est @user.books.

    Enfin ta requete pourait se décrire en language humain par :
    dans les livres de @user, je veux celui qui à l'id égal à params[:id]
    Elle donne donc des livres et pas des users comme pourait laisser le croire le nom donné à ta variable @users_all.

    Ensuite, en rails, le join pour sortire des résultats de plusieurs tables en même temps n'a pas vraiment de sens.
    Je m'explique:

    Dans le cas de ta structure User Role Language, tu cherches un User par son id et tu veux son role et son language. la bonne requete toute simple est

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @user = User.find(params[:id]) #la valeur de params[:id] étant un id d'utilisateur
    ensuite pour accéder à la langue depuis @user, tu fais @user.language
    ce qui va relancer une requete et te donner l'objet language lié à l'utilisateur.
    Pareil pour le role @user.role.

    Si tu veux pour des raisons d'optimisation ne pas relancer de requete a l'acces des objets liés, tu utilises la methode include.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @user = User.includes(:language, :role).where(:id => params[:id])
    Ceci va mettre en cache les objets Language et Role associés et ne relancera pas de requête à l'accès de ces derniers. On appelle ceci le eager loading.

    En manipulant les modèles avec Rails, il faut penser Rails et non pas SQL.

  7. #7
    Membre habitué
    Inscrit en
    Février 2004
    Messages
    279
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 279
    Points : 164
    Points
    164
    Par défaut
    Merci beaucoup, j'apprecie votre aide.

    Je comprends mieux la facon de penser.
    J'essayais d'utiliser des joins de partout pour limiter l'access a la base, pour ne pas avoir a relancer les requetes. Mais je vais, a present, utiliser le include.

    Vous avez tout a fait raison, il faut tenter de penser Rails et non pas Sql.
    Il faut pratiquer, pratiquer et encore pratiquer, mais ca viendra

    Pour le user.books (mon user has_many books) je vais regarder pourquoi cela ne marche pas...

    En tout cas merci!
    Sand

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 21/01/2010, 05h12
  2. Réponses: 2
    Dernier message: 22/08/2007, 00h02
  3. Int 21H AX=716Ch ne fait pas mon affaire !!
    Par TheBigMac dans le forum Assembleur
    Réponses: 4
    Dernier message: 10/09/2004, 21h51
  4. Pb de selection qui ne se fait pas
    Par Stef.proxi dans le forum Langage SQL
    Réponses: 4
    Dernier message: 06/08/2004, 11h54
  5. [SQL Server 8] le join ne se fait pas
    Par Baquardie dans le forum Langage SQL
    Réponses: 10
    Dernier message: 29/07/2004, 15h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo