A Little Background: I''m writing a soon-to-be-open-sourced library management application for small organizations. I''ll probably have more questions as I progress, but for now: Why would something like this not be functionally identical? copies is a has_many AR expansion, and returned? returns a boolean value. copies.find_all {|c| c.returned?}.length -> 3 copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 Any ideas? Thanks, Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org>
Oh, this one bit me bad. So, for some reason, that I don''t yet understand, even though a has_many accessor returns an Array, it''s find_all method is overridden by something else. How do I know this?>> Book.find(1).copies.select {|c| c.returned?}.length=> 2>> Book.find(1).copies.find_all {|c| c.returned?}.length=> 3>> Book.find(1).copies.select {|c| false}=> []>> Book.find(1).copies.find_all {|c| false}=> [#<Copy:0xb75f5c38 @attributes={"number"=>"1", "id"=>"2", "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>, #<Copy:0xb75f5bfc @attributes={"number"=>"2", "id"=>"3", "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>, #<Copy:0xb75f5bc0 @attributes={"number"=>"3", "id"=>"4", "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>] Can someone explain this completely unintuitive behavior? I understand that find_all is a somewhat deprecated (vs. find(:all) Ruby accessor in ActiveRecord, but it should only be present on individual objects, *not* a collection of objects. Now, I''ve only really been working with Rails since OSCON, but I think this could be a bug. Any ideas? Thanks, Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> On 8/14/05, Chris Lambert <clambert-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> A Little Background: I''m writing a soon-to-be-open-sourced library > management application for small organizations. I''ll probably have > more questions as I progress, but for now: > > Why would something like this not be functionally identical? copies is > a has_many AR expansion, and returned? returns a boolean value. > > copies.find_all {|c| c.returned?}.length -> 3 > copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 > > Any ideas? > > Thanks, > > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> >
Chris Lambert wrote:>A Little Background: I''m writing a soon-to-be-open-sourced library >management application for small organizations. I''ll probably have >more questions as I progress, but for now: > >Why would something like this not be functionally identical? copies is >a has_many AR expansion, and returned? returns a boolean value. > >copies.find_all {|c| c.returned?}.length -> 3 >copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 > > >I recall (vaguely) an earlier discussion on this and "Duck Typing" (see Pick-Axe book). The find returns an array and sorta behaves as one but isn''t. rows = Model.find() rows.something may will give different results than Model.find().something
im going to assume your trying to use it wrong. and further going to assume find_all doesnt ever yield the block given to it, which makes the { |c| false} or { |c| c.returned? } useless. On 8/14/05, Chris Lambert <clambert-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Oh, this one bit me bad. > > So, for some reason, that I don''t yet understand, even though a > has_many accessor returns an Array, it''s find_all method is overridden > by something else. How do I know this? > > >> Book.find(1).copies.select {|c| c.returned?}.length > => 2 > >> Book.find(1).copies.find_all {|c| c.returned?}.length > => 3 > > >> Book.find(1).copies.select {|c| false} > => [] > >> Book.find(1).copies.find_all {|c| false} > => [#<Copy:0xb75f5c38 @attributes={"number"=>"1", "id"=>"2", > "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>, > #<Copy:0xb75f5bfc @attributes={"number"=>"2", "id"=>"3", > "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>, > #<Copy:0xb75f5bc0 @attributes={"number"=>"3", "id"=>"4", > "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>] > > Can someone explain this completely unintuitive behavior? I understand > that find_all is a somewhat deprecated (vs. find(:all) Ruby accessor > in ActiveRecord, but it should only be present on individual objects, > *not* a collection of objects. > > Now, I''ve only really been working with Rails since OSCON, but I think > this could be a bug. Any ideas? > > Thanks, > > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> > > On 8/14/05, Chris Lambert <clambert-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > A Little Background: I''m writing a soon-to-be-open-sourced library > > management application for small organizations. I''ll probably have > > more questions as I progress, but for now: > > > > Why would something like this not be functionally identical? copies is > > a has_many AR expansion, and returned? returns a boolean value. > > > > copies.find_all {|c| c.returned?}.length -> 3 > > copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 > > > > Any ideas? > > > > Thanks, > > > > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- Zachery Hostens <zacheryph-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Aug 14, 2005, at 3:18 PM, Chris Lambert wrote:> Oh, this one bit me bad. > > So, for some reason, that I don''t yet understand, even though a > has_many accessor returns an Array, it''s find_all method is overridden > by something else. How do I know this? >. . .> Can someone explain this completely unintuitive behavior? I understand > that find_all is a somewhat deprecated (vs. find(:all) Ruby accessor > in ActiveRecord, but it should only be present on individual objects, > *not* a collection of objects. > > Now, I''ve only really been working with Rails since OSCON, but I think > this could be a bug. Any ideas? > > Thanks, > > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> >Hey Chris, It''s not a bug and it''s not _really_ an Array you''re getting back from the association. The associations are done by the magic of AssociationCollection and AssociationProxy and friends. Note in AR''s associations/has_many_association.rb that #find_all is in fact not #select, as one would deduce thinking they had an Array. #find_all was meant to act just like Model.find_all so that you could use the power of SQL conditions in both cases. #select is not proxied, so that will behave as you''d expect. -Scott
I understand duck typing, but the example you provided just seems like bad lanuage design. Unless there is some type coercing going on with rows'' initial "type", I would hope the two expressions produced equivelent results. -- Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> On 8/14/05, Steve Downey <sldowney-TVLZxgkOlNX2fBVCVOL8/A@public.gmane.org> wrote:> Chris Lambert wrote: > > >A Little Background: I''m writing a soon-to-be-open-sourced library > >management application for small organizations. I''ll probably have > >more questions as I progress, but for now: > > > >Why would something like this not be functionally identical? copies is > >a has_many AR expansion, and returned? returns a boolean value. > > > >copies.find_all {|c| c.returned?}.length -> 3 > >copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 > > > > > > > > I recall (vaguely) an earlier discussion on this and "Duck Typing" (see > Pick-Axe book). > > The find returns an array and sorta behaves as one but isn''t. > > rows = Model.find() > rows.something > > may will give different results than > > Model.find().something > >
I was trying to use the find_all present in Enumerable, but apparently that isn''t how it works. I think the uses of inject and select are correct if this was in fact an Array. You''re right that it doesn''t yield to the block, it was just for example''s sake. -- Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> On 8/14/05, Zachery Hostens <zacheryph-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> im going to assume your trying to use it wrong. > > and further going to assume find_all doesnt ever yield the block given > to it, which makes the { |c| false} or { |c| c.returned? } useless. > > On 8/14/05, Chris Lambert <clambert-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Oh, this one bit me bad. > > > > So, for some reason, that I don''t yet understand, even though a > > has_many accessor returns an Array, it''s find_all method is overridden > > by something else. How do I know this? > > > > >> Book.find(1).copies.select {|c| c.returned?}.length > > => 2 > > >> Book.find(1).copies.find_all {|c| c.returned?}.length > > => 3 > > > > >> Book.find(1).copies.select {|c| false} > > => [] > > >> Book.find(1).copies.find_all {|c| false} > > => [#<Copy:0xb75f5c38 @attributes={"number"=>"1", "id"=>"2", > > "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>, > > #<Copy:0xb75f5bfc @attributes={"number"=>"2", "id"=>"3", > > "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>, > > #<Copy:0xb75f5bc0 @attributes={"number"=>"3", "id"=>"4", > > "location_id"=>"1", "person_id"=>"1", "book_id"=>"1"}>] > > > > Can someone explain this completely unintuitive behavior? I understand > > that find_all is a somewhat deprecated (vs. find(:all) Ruby accessor > > in ActiveRecord, but it should only be present on individual objects, > > *not* a collection of objects. > > > > Now, I''ve only really been working with Rails since OSCON, but I think > > this could be a bug. Any ideas? > > > > Thanks, > > > > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> > > > > On 8/14/05, Chris Lambert <clambert-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > A Little Background: I''m writing a soon-to-be-open-sourced library > > > management application for small organizations. I''ll probably have > > > more questions as I progress, but for now: > > > > > > Why would something like this not be functionally identical? copies is > > > a has_many AR expansion, and returned? returns a boolean value. > > > > > > copies.find_all {|c| c.returned?}.length -> 3 > > > copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 > > > > > > Any ideas? > > > > > > Thanks, > > > > > > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> > > > > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > -- > Zachery Hostens <zacheryph-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Scott, thanks for the helpful reply.> It''s not a bug and it''s not _really_ an Array you''re getting back from > the association.The object''s class method did in fact return Array. I knew there was some magic going on, but I assumed that even so, the standard Array instance methods would be available.> The associations are done by the magic of AssociationCollection and > AssociationProxy > and friends. Note in AR''s associations/has_many_association.rb that > #find_all is in fact > not #select, as one would deduce thinking they had an Array. #find_all > was meant to act > just like Model.find_all so that you could use the power of SQL > conditions in both cases. > #select is not proxied, so that will behave as you''d expect.How can you have the full power of SQL conditions if there isn''t another round-trip with SQL? If I run a query (via a has_many), and get back a subset of rows--there''s no reasonable way for me to run a query on just the rows in the resultset--is there? If there is, I would be interested, but otherwise I''m confused. I''ll dig through the source code to try and find out, but any insight you can share would be appreciated. -- Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org>> > -Scott > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
It seems like find_all on a has_many association is actually deprecated according to the comments. I wish this was documented somewhere, but I guess there''s no real place to document it since we''re supposed to ignore the fact it''s anything but an array. I guess my complaint is that it doesn''t follow the principle of least surprise, but that could be why it was deprecated. Thanks for the help, I''ll keep using select for now. -- Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> On 8/14/05, Chris Lambert <clambert-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Scott, thanks for the helpful reply. > > > It''s not a bug and it''s not _really_ an Array you''re getting back from > > the association. > > The object''s class method did in fact return Array. I knew there was > some magic going on, but I assumed that even so, the standard Array > instance methods would be available. > > > The associations are done by the magic of AssociationCollection and > > AssociationProxy > > and friends. Note in AR''s associations/has_many_association.rb that > > #find_all is in fact > > not #select, as one would deduce thinking they had an Array. #find_all > > was meant to act > > just like Model.find_all so that you could use the power of SQL > > conditions in both cases. > > #select is not proxied, so that will behave as you''d expect. > > How can you have the full power of SQL conditions if there isn''t > another round-trip with SQL? If I run a query (via a has_many), and > get back a subset of rows--there''s no reasonable way for me to run a > query on just the rows in the resultset--is there? If there is, I > would be interested, but otherwise I''m confused. I''ll dig through the > source code to try and find out, but any insight you can share would > be appreciated. > > -- > Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> > > > > > > > > > -Scott > > > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > >
Chris Lambert wrote:>A Little Background: I''m writing a soon-to-be-open-sourced library >management application for small organizations. I''ll probably have >more questions as I progress, but for now: > >Why would something like this not be functionally identical? copies is >a has_many AR expansion, and returned? returns a boolean value. > >copies.find_all {|c| c.returned?}.length -> 3 >copies.inject(0) {|i, c| i + ((c.returned?) ? 1 : 0)} -> 2 > >Any ideas? > >Thanks, > >Chris Lambert <chris-1vnkWVZi4QaVc3sceRu5cw@public.gmane.org> >_______________________________________________ >Rails mailing list >Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >http://lists.rubyonrails.org/mailman/listinfo/rails > > > >ActiveRecord associations seem to overwrite the default Enumerable find_all definition with its own. It is calling the ActiveRecord style find_all. So the block is ignored, it is simply returning all records. Try using select, that is an alias for find_all and is not overridden by ActiveRecord. -- Jack Christensen jackc-/SOt/BrQZzOj3I+7jmQ39gC/G2K4zDHf@public.gmane.org