Hi all I am new to Rails, and obviously I''m missing something, I''ll get straight to the question: A User has many operations (granted to her), each Operation is associated with an OperationType. Each Operation may be associated with more then one User. So the model goes like this: class User < ActiveRecord::Base has_and_belongs_to_many :operations end class Operation <ActiveRecord::Base belongs_to :operation_type, has_and_belongs_to_many :users end class OperationType <ActiveRecord::Base has_many :operations end And I have users, operations, operations_users (join table) & operation_types tables as needed. Now for a given user, I want to fetch all the types of the operations associated with her (OperationType classes). So there is one very inefficient way that goes like this: (suppose user_id holds the user id) user = User.find(user_id) user_operations = user.operations @user_operation_types = Array.new for op in user_operations operation_type = op.operation_type if !@user_operation_types.include? operation_type @user_operation_types << operation_type end end And I get all the operation types associated with the user''s operations in the @user_operation_types array. But this is inefficient (many selects) and doesn''t seem good. I tried to change the first line to: user = User.find(user_id, :include=> :operations) but then I get only one entry in the @user_operation_types array, which is incorrect (there should be more). What is the right way to do this? Thanks for your help Nadav __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Hi all I am new to Rails, and obviously I''m missing something, I''ll get straight to the question: A User has many operations (granted to her), each Operation is associated with an OperationType. Each Operation may be associated with more then one User. So the model goes like this: class User < ActiveRecord::Base has_and_belongs_to_many :operations end class Operation <ActiveRecord::Base belongs_to :operation_type, has_and_belongs_to_many :users end class OperationType <ActiveRecord::Base has_many :operations end And I have users, operations, operations_users (join table) & operation_types tables as needed. Now for a given user, I want to fetch all the types of the operations associated with her (OperationType classes). So there is one very inefficient way that goes like this: (suppose user_id holds the user id) user = User.find(user_id) user_operations = user.operations @user_operation_types = Array.new for op in user_operations operation_type = op.operation_type if !@user_operation_types.include? operation_type @user_operation_types << operation_type end end And I get all the operation types associated with the user''s operations in the @user_operation_types array. But this is inefficient (many selects) and doesn''t seem good. I tried to change the first line to: user = User.find(user_id, :include=> :operations) but then I get only one entry in the @user_operation_types array, which is incorrect (there should be more). What is the right way to do this? Thanks for your help Nadav
Hey man, I don''t understand why you want to say "user_operations" instead of "user.operations" when it''s just one character different? Anyway, I''d go: user = User.find(user_id) @user_operation_types = user.operations.inject(Array.new) do | a, op | opt = op.operation_type if a.include? opt a else a << opt end end Julian. On 28/08/2005, at 9:16 PM, Nadav Blum wrote:> Hi all > I am new to Rails, and obviously I''m missing something, I''ll get > straight to the question: >...> (suppose user_id holds the user id) > user = User.find(user_id) > user_operations = user.operations > @user_operation_types = Array.new > for op in user_operations > operation_type = op.operation_type > if !@user_operation_types.include? operation_type > @user_operation_types << operation_type > end > end > > And I get all the operation types associated with the user''s > operations in the @user_operation_types array. But this is > inefficient (many selects) and doesn''t seem good. > I tried to change the first line to: > user = User.find(user_id, :include=> :operations) > but then I get only one entry in the @user_operation_types array, > which is incorrect (there should be more). > > What is the right way to do this? > > Thanks for your help > Nadav > > > > > > __________________________________________________ > Do You Yahoo!? > Tired of spam? Yahoo! Mail has the best spam protection around > http://mail.yahoo.com > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >_______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Actually even better: user = User.find(user_id) @user_operation_types = user.operations.inject(Array.new) { | a, op | a << opt unless a.include? op.operation_type; a } Julian. On 29/08/2005, at 12:57 PM, Julian Leviston wrote:> Hey man, > > I don''t understand why you want to say "user_operations" instead of > "user.operations" when it''s just one character different? > > Anyway, I''d go: > > user = User.find(user_id) > @user_operation_types = user.operations.inject(Array.new) do | a, op | > opt = op.operation_type > if a.include? opt > a > else > a << opt > end > end > > Julian. > > On 28/08/2005, at 9:16 PM, Nadav Blum wrote: > >> Hi all >> I am new to Rails, and obviously I''m missing something, I''ll get >> straight to the question: >> > ... >> (suppose user_id holds the user id) >> user = User.find(user_id) >> user_operations = user.operations >> @user_operation_types = Array.new >> for op in user_operations >> operation_type = op.operation_type >> if !@user_operation_types.include? operation_type >> @user_operation_types << operation_type >> end >> end >> >> And I get all the operation types associated with the user''s >> operations in the @user_operation_types array. But this is >> inefficient (many selects) and doesn''t seem good. >> I tried to change the first line to: >> user = User.find(user_id, :include=> :operations) >> but then I get only one entry in the @user_operation_types array, >> which is incorrect (there should be more). >> >> What is the right way to do this? >> >> Thanks for your help >> Nadav >> >> >> >> >> >> __________________________________________________ >> Do You Yahoo!? >> Tired of spam? Yahoo! Mail has the best spam protection around >> http://mail.yahoo.com >> >> _______________________________________________ >> Rails mailing list >> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> >_______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
> > > Actually even better: > > user = User.find(user_id) > <at> user_operation_types = user.operations.inject(Array.new) { | a, op | a<< opt unless a.include? op.operation_type; a }> > Julian. > > > On 29/08/2005, at 12:57 PM, Julian Leviston wrote: > Hey man, > I don''t understand why you want to say "user_operations" insteadof "user.operations" when it''s just one character different?> > Anyway, I''d go: > > user = User.find(user_id) > <at> user_operation_types = user.operations.inject(Array.new) do | a, op | > opt = op.operation_type > if a.include? opt > a > else > a << opt > end > end > > Julian. > > > On 28/08/2005, at 9:16 PM, Nadav Blum wrote: > Hi all I am new to Rails, and obviously I''m missing something, I''ll getstraight to the question:> ... > (suppose user_id holds the user id) user = User.find(user_id)user_operations = user.operations <at> user_operation_types = Array.new for op in user_operations operation_type = op.operation_type if ! <at> user_operation_types.include? operation_type <at> user_operation_types << operation_type end end And I get all the operation types associated with the user''s operations in the <at> user_operation_types array. But this is inefficient (many selects) and doesn''t seem good. I tried to change the first line to: user = User.find (user_id, :include=> :operations) but then I get only one entry in the <at> user_operation_types array, which is incorrect (there should be more). What is the right way to do this? Thanks for your help Nadav> > > __________________________________________________Do You Yahoo!?Tired ofspam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com> _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > > > > > > _______________________________________________ > Rails mailing list > Rails@... > http://lists.rubyonrails.org/mailman/listinfo/rails >Julian Thanks, as you saw I am also a bit fresh in ruby programming... While using ''inject'' is indeed elegant and short, there is still a problem of issuing many ''select'' commands to the db - one for each operation (by calling op.operation_type). So is there a way to use an ":includes" parameter or something like that in order to preload the operation_type data? Maybe I''ll just use a find_by_sql like User.find_by_sql(["select distinct operation_types.* " + "FROM users, operations_users, operations, operation_types " + "WHERE users.id = ? " + "AND users.id = operations_users.user_id " + "AND operations_users.operation_id = operations.id " + "AND operations.operation_type_id = operation_types.id", user_id]) in order to fetch the whole list in one select command (doesn''t look nice but pmaybe more efficient)? Thanks Nadav
On 30/08/2005, at 8:41 PM, Nadav Blum wrote:>> >> Anyway, I''d go: >> >> user = User.find(user_id) >> <at> user_operation_types = user.operations.inject(Array.new) do >> | a, op | >> opt = op.operation_type >> if a.include? opt >> a >> else >> a << opt >> end >> end >> >> Julian. >> > > Julian > Thanks, as you saw I am also a bit fresh in ruby programming... > While using ''inject'' is indeed elegant and short, there is still a > problem > of issuing many ''select'' commands to the db - one for each > operation (by > calling op.operation_type). So is there a way to use an ":includes" > parameter or something like that in order to preload the > operation_type data? > Maybe I''ll just use a find_by_sql like > User.find_by_sql(["select distinct operation_types.* " + > "FROM users, operations_users, operations, operation_types " + > "WHERE users.id = ? " + > "AND users.id = operations_users.user_id " + > "AND operations_users.operation_id = operations.id " + > "AND operations.operation_type_id = operation_types.id", user_id]) > > in order to fetch the whole list in one select command (doesn''t > look nice but > pmaybe more efficient)? > > Thanks > > NadavYou''re kidding! Surely ActiveRecord auto-gets the data from neighbouring objects doesn''t it? Is this multiple-select problem you''re talking about something you''ve actually seen from looking at the logs, or are you assuming the way the framework has been coded? If you''re right, and Rails has been coded in this inefficient manner, I''m a bit disturbed! Julian. _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Look up "eager loading". It''s not as inefficient as you think to not load *every single related table* on every record load. But you can specify doing so using that method. On 9/4/05, Julian Leviston <julian-AfxEtdRqmE/tt0EhB6fy4g@public.gmane.org> wrote:> > > On 30/08/2005, at 8:41 PM, Nadav Blum wrote: > > > Anyway, I''d go: > > user = User.find(user_id) > <at> user_operation_types = user.operations.inject(Array.new) do | a, op | > opt = op.operation_type > if a.include? opt > a > else > a << opt > end > end > > Julian. > > > Julian > Thanks, as you saw I am also a bit fresh in ruby programming... > While using ''inject'' is indeed elegant and short, there is still a problem > of issuing many ''select'' commands to the db - one for each operation (by > calling op.operation_type). So is there a way to use an ":includes" > parameter or something like that in order to preload the operation_type > data? > Maybe I''ll just use a find_by_sql like > User.find_by_sql(["select distinct operation_types.* " + > "FROM users, operations_users, operations, operation_types " + > "WHERE users.id <http://users.id> = ? " + > "AND users.id <http://users.id> = operations_users.user_id " + > "AND operations_users.operation_id = operations.id <http://operations.id>" + > "AND operations.operation_type_id = operation_types.id", user_id]) > > in order to fetch the whole list in one select command (doesn''t look nice > but > pmaybe more efficient)? > > Thanks > > Nadav > > > > You''re kidding! Surely ActiveRecord auto-gets the data from neighbouring > objects doesn''t it? > > Is this multiple-select problem you''re talking about something you''ve > actually seen from looking at the logs, or are you assuming the way the > framework has been coded? > > If you''re right, and Rails has been coded in this inefficient manner, I''m > a bit disturbed! > > Julian. > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > >_______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails