Forum: Italian Ruby user group undefined method 'each' for ...

Posted by Marco Mueller (marco_m)
on 2009-06-10 13:35
Salve a tutti,

sto lavorando al mio primo progetto Rails (implementazione di un
registro di classe elettronico) e mi sto dannando da alcune ore su qs
poche righe:

ho 3 model: Teacher, Rclass e Pupil,
Teacher e Rclass sono legati da una relazione molti a molti,
Pupil e Rclass sono legati da una relazione 1 a molti,

voglio che la variabile @pupils contenga tutti gli alunni delle classi
associate ad un insegnante (@teach)

Mi dà:
UNDEFINED METHOD 'EACH' FOR #<Pupil:0x5e9dd24>

Qualcuno mi dice dove sbaglio? ;-)

Penso sia il FIND ma non so come altro esprimermi...

...
    @teach = Teacher.find(@current_user.teacher_id)
    @rclasses = @teach.rclasses
    @pupils = []
    for rclass in @rclasses
      @pups_rclass = Pupil.find_by_rclass_id(rclass.id)
      for pups_rclass in @pups_rclass
        @pupils << pups_rclass
      end
    end
...
Posted by Silvano Stralla (sistrall)
on 2009-06-10 14:16
(Received via mailing list)
Ciao,

il problema potrebbe stare in

   @pups_rclass = Pupil.find_by_rclass_id(rclass.id)

Tu ti aspetti che restituisca un array di oggetti Pupils, mentre
find_by_rclass_id restituisce il primo record che soddisfa la
condizione. Prova con:

   @pups_rclass = Pupil.find_by_all_rclass_id(rclass.id)

Ciao,
Silvano


2009/6/10 Marco Mueller <mlrmarco@hotmail.com>:
> voglio che la variabile @pupils contenga tutti gli alunni delle classi
>    @rclasses = @teach.rclasses
> _______________________________________________
> Ml mailing list
> Ml@lists.ruby-it.org
> http://lists.ruby-it.org/mailman/listinfo/ml
>



--
Considera l'ambiente prima di stampare questa email. Dai, che
l'equazione è semplice: meno A4, più alberi.


. . . Silvano Stralla . . .
email: silvano.stralla@sistrall.it
site: http://www.sistrall.it
Posted by Marco Mastrodonato (marcomd)
on 2009-06-10 15:35
Ciao Marco,
cerco di interpretarti il messaggio che ricevi, è importante capire gli 
errori per non ripeterli: il metodo each non è definito perchè viene 
richiamato su un oggetto pupil mentre deve essere fatto su un array per 
scorrere gli elementi.

un alternativa al consiglio di Silvano è una novità di rails 2.3

@pups_rclass = Pupil.scoped_by_rclass_id(rclass.id)

find_by effettua una find(:first) che restituisce un solo oggetto
scoped_by una find(:all) che restituisce un array di oggetti

inoltre se vuoi anche avere un occhio di riguardo sulle prestazioni 
potresti utilizzare direttamente una find, richiamare un metodo dinamico 
è figo ma dispendioso

@pups_rclass = Pupil.find :all, :conditions => ["rclass_id = ?", 
rclass.id]
Posted by Marco Mueller (marco_m)
on 2009-06-10 16:29
Silvano e Marco, GRAZIE MILLEEE!
Da solo non ne sarei venuto fuori... funziona molto bene!
Marco
Posted by Msan Msan (msan)
on 2009-06-11 10:18
(Received via mailing list)
2009/6/10 Marco Mastrodonato <m.mastrodonato@gmail.com>:
> Ciao Marco,
> cerco di interpretarti il messaggio che ricevi, è importante capire gli
> errori per non ripeterli: il metodo each non è definito perchè viene
> richiamato su un oggetto pupil mentre deve essere fatto su un array per
> scorrere gli elementi.
>
> un alternativa al consiglio di Silvano è una novità di rails 2.3
>
> @pups_rclass = Pupil.scoped_by_rclass_id(rclass.id)

La scoped_by rispetto alla find_by che fa di diverso?
Posted by Paolo Montrasio (pmontrasio)
on 2009-06-12 16:07
Msan Msan wrote:
> 2009/6/10 Marco Mastrodonato <m.mastrodonato@gmail.com>:
>> Ciao Marco,
>> cerco di interpretarti il messaggio che ricevi, � importante capire gli
>> errori per non ripeterli: il metodo each non � definito perch� viene
>> richiamato su un oggetto pupil mentre deve essere fatto su un array per
>> scorrere gli elementi.
>>
>> un alternativa al consiglio di Silvano � una novit� di rails 2.3
>>
>> @pups_rclass = Pupil.scoped_by_rclass_id(rclass.id)
> 
> La scoped_by rispetto alla find_by che fa di diverso?

La spiegazione migliore tutto sommato mi sembra il manuale di 
ActiveRecord::NamedScope::ClassMethods nel sito ufficiale dell'API di 
Rails

http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html
http://api.rubyonrails.org/classes/ActiveRecord/NamedScope.html

Riporto un piccolo estratto del primo, ma nel doc ci sono tante altre 
cose interessanti:

--------------
  class Shirt < ActiveRecord::Base
    named_scope :red, :conditions => {:color => 'red'}
    named_scope :dry_clean_only, :joins => :washing_instructions, 
:conditions => ['washing_instructions.dry_clean_only = ?', true]
  end

The above calls to named_scope define class methods Shirt.red and 
Shirt.dry_clean_only. Shirt.red, in effect, represents the query 
Shirt.find(:all, :conditions => {:color => ‘red’}).

Unlike Shirt.find(...), however, the object returned by Shirt.red is not 
an Array; it resembles the association object constructed by a has_many 
declaration. For instance, you can invoke Shirt.red.find(:first), 
Shirt.red.count, Shirt.red.find(:all, :conditions => {:size => 
‘small’}).
--------------

Utile per crearsi i propri metodi risparmiando caratteri, conditions e 
bug dovuti a copiature e mancati aggiornamenti. Rende Rails più DRY.

scoped_by è un metodo dinamico che crea gli scope al volo. La 
documentazione non è granché. Ne ho trovata dentro a
lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb, 
davanti al metodo method_missing che intercetta tutte le chiamate a 
metodi non definiti (è il meccanismo con cui funzionano i find_by). 
Riporto:

--------------
[method_missing] Enables dynamic finders like 
find_by_user_name(user_name) and 
find_by_user_name_and_password(user_name, password)
that are turned into find(:first, :conditions => ["user_name = ?", 
user_name]) and find(:first, :conditions => ["user_name = ? AND password 
= ?", user_name, password]) respectively.
Also works for find(:all) by using find_all_by_amount(50) that is turned 
into find(:all, :conditions => ["amount = ?", 50]).

It's even possible to use all the additional parameters to +find+. For 
example, the full interface for +find_all_by_amount+ is actually 
find_all_by_amount(amount, options)-

Also enables dynamic scopes like scoped_by_user_name(user_name) and 
scoped_by_user_name_and_password(user_name, password) that
are turned into scoped(:conditions => ["user_name = ?", user_name]) and 
scoped(:conditions => ["user_name = ? AND password = ?", user_name, 
password]) respectively.

Each dynamic finder, scope or initializer/creator is also defined in the 
class after it is first invoked, so that future
---------------


Paolo
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.