Michael Smedberg
2005-Sep-21 22:21 UTC
Elegant way to filter HABTM collection dynamically?
I feel like I''m missing something in has_and_belongs_to_many. I''m working on a calendaring app where calendars habtm events (i.e. calendars have lists of events, but events can appear on more than one calendar.) I''d like to do something like "@calendar.events", but filter by a date range (e.g. all of the events for the next week.) I managed to write code to do this, but I''m wondering if there''s a more standard way to do this- is this a problem that has already been solved? I did this by adding a new option to HABTM, but it involves overriding existing functionality, so it''s a little ugly. My solution overrides the has_and_belongs_to_many method to recognize an option called :dynamic_conditions, then adding this code to ActiveRecord::Associations::HasAndBelongsToManyAssociation::construct_sql: if @options[:dynamic_conditions] dyn_cond = @owner.send(@options[:dynamic_conditions]) @finder_sql << " AND #{interpolate_sql(dyn_cond)}" if dyn_cond end With those changes, I''m able to include logic like this in my model: has_and_belongs_to_many :events, :order => ''start'', :dynamic_conditions => ''get_dynamic_conditions'' def set_dynamic_conditions(cond) @cond = cond end def get_dynamic_conditions #MES- Just an example return "cal_evt_status = #{@cond}" end Then, in my controller, I can do this: cal.set_dynamic_conditions(0) evts = cal.events It seems to work pretty well, but it requires changing Rails code- is there a better way to do this? Thanks! _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
On Sep 21, 2005, at 6:21 PM, Michael Smedberg wrote:> I''d like to do something like "@calendar.events", but filter by a > date range (e.g. all of the events for the next week.) I managed > to write code to do this, but I''m wondering if there''s a more > standard way to do this- is this a problem that has already been > solved?I think you''re looking for: @calendar.events.find() -- -- Tom Mornini
Michael Smedberg
2005-Sep-22 00:15 UTC
Re: Elegant way to filter HABTM collection dynamically?
No dice, when my code looks like this: evts = cal.events.find(:all, :condition => ''2 = 2'') the log looks like this: ActiveRecord::RecordNotFound (Couldn''t find Event with ID in (''--- :all'',''--- \n:condition: 2 = 2'')): and in fact if I just use "find(:all)", I get a similar error: ActiveRecord::RecordNotFound (Couldn''t find Event with ID in (''--- :all'')) When I try "cal.events.find_by_sql", I get an undefined method error (specifically, "NoMethodError (undefined method `find_by_sql'' for #<Array:0x5f41c48>)".) Further, I added some print statements to the find method in has_and_belongs_to_many_association.rb, and they never get hit (well, I don''t see them, anyway.) If I add "breakpoint" to the code there, it also isn''t hit- it seems like calling cal.events.find does NOT call the find from has_and_belongs_to_many_association.rb. I''d guess that it calls the "find" method that Array inherits from Enumerable. Does that seem right? On 9/21/05, Tom Mornini <tmornini-W/9V78bTXriB+jHODAdFcQ@public.gmane.org> wrote:> > OK, how about: > find( :all, > :condition => ) > > similarly with find_by_sql. > > -- > -- Tom Mornini > > > On Sep 21, 2005, at 7:39 PM, Michael Smedberg wrote: > > I think that you may well be right, but what are the arguments to find? > The doc on http://api.rubyonrails.com says: > > collection.find(id) - finds an associated object responding to the id and > that meets the condition that it has to be associated with this object. > > I was thinking it might be something like this: > > args = {:conditions => ''2 = 2''} > evts = cal.events.find(args) > > but that throws an error like this: > > Couldn''t find Event with ID in (''--- \n:conditions: 2 = 2'') > > > Thanks! > > On 9/21/05, Tom Mornini <tmornini-W/9V78bTXriB+jHODAdFcQ@public.gmane.org> wrote: > > > > On Sep 21, 2005, at 6:21 PM, Michael Smedberg wrote: > > > > > I''d like to do something like "@calendar.events", but filter by a > > > date range (e.g. all of the events for the next week.) I managed > > > to write code to do this, but I''m wondering if there''s a more > > > standard way to do this- is this a problem that has already been > > > solved? > > > > I think you''re looking for: > > > > @calendar.events.find() > > > > -- > > -- Tom Mornini > > > > > > > >_______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Andrew Stone
2005-Sep-22 00:38 UTC
Re: Elegant way to filter HABTM collection dynamically?
> > > evts = cal.events.find (args) > > > >I think you need to use use cal.events.find(:all, :conditions => ''2=2''). Without using :all or :first it is trying to find by id. Hence the error: Couldn''t find Event with ID in (''--- \n:conditions: 2 = 2'') -- Andrew Stone _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
In article <eb88ec4105092117387a4610d5-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>, stonelists- Re5JQEeQqe8AvxtiuMwx3w-XMD5yJDbdMReXY1tMh2IBg@public.gmane.org says...> I think you need to use use cal.events.find(:all, :conditions => ''2=2''). > Without using :all or :first it is trying to find by id. Hence the error:Nope - believe it or not, there ARE no such forms of find for habtm! I discovered this the other day trying to answer someone in IRC. Why, of course you can get find() to work, you just.. um... oh. It''s a pretty gaping hole, really. cal.events is an Array, so all you can do to search is select() or its opposite (which escapes me). Seems like you should be able to use the other find syntaxes as syntactic sugar, but it''s never been coded. -- Jay Levitt | Wellesley, MA | I feel calm. I feel ready. I can only Faster: jay at jay dot fm | conclude that''s because I don''t have a http://www.jay.fm | full grasp of the situation. - Mark Adler
Pat Maddox
2005-Sep-22 05:32 UTC
Re: Re: Elegant way to filter HABTM collection dynamically?
On 9/21/05, Jay Levitt <jay-news-WxwZQdyI2t0@public.gmane.org> wrote:> In article <eb88ec4105092117387a4610d5-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>, stonelists- > Re5JQEeQqe8AvxtiuMwx3w-XMD5yJDbdMReXY1tMh2IBg@public.gmane.org says... > > I think you need to use use cal.events.find(:all, :conditions => ''2=2''). > > Without using :all or :first it is trying to find by id. Hence the error: > > Nope - believe it or not, there ARE no such forms of find for habtm! > I discovered this the other day trying to answer someone in IRC. Why, > of course you can get find() to work, you just.. um... oh. > > It''s a pretty gaping hole, really. cal.events is an Array, so all you > can do to search is select() or its opposite (which escapes me). Seems > like you should be able to use the other find syntaxes as syntactic > sugar, but it''s never been coded. > > -- > Jay Levitt | > Wellesley, MA | I feel calm. I feel ready. I can only > Faster: jay at jay dot fm | conclude that''s because I don''t have a > http://www.jay.fm | full grasp of the situation. - Mark Adler > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >Okay I don''t have any of the code on me, but you have to use a join. This is because AR doesn''t automatically do joins for HABTM for some reason. At first I used find_by_sql and just manually did the join, but I''m pretty sure there''s a :join keyword that you can use to hook it up and use within find(). Pat
Joe Van Dyk
2005-Sep-22 05:41 UTC
Re: Re: Elegant way to filter HABTM collection dynamically?
On 9/21/05, Pat Maddox <pergesu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 9/21/05, Jay Levitt <jay-news-WxwZQdyI2t0@public.gmane.org> wrote: > > In article <eb88ec4105092117387a4610d5-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>, stonelists- > > Re5JQEeQqe8AvxtiuMwx3w-XMD5yJDbdMReXY1tMh2IBg@public.gmane.org says... > > > I think you need to use use cal.events.find(:all, :conditions => ''2=2''). > > > Without using :all or :first it is trying to find by id. Hence the error: > > > > Nope - believe it or not, there ARE no such forms of find for habtm! > > I discovered this the other day trying to answer someone in IRC. Why, > > of course you can get find() to work, you just.. um... oh. > > > > It''s a pretty gaping hole, really. cal.events is an Array, so all you > > can do to search is select() or its opposite (which escapes me). Seems > > like you should be able to use the other find syntaxes as syntactic > > sugar, but it''s never been coded. > > > > -- > > Jay Levitt | > > Wellesley, MA | I feel calm. I feel ready. I can only > > Faster: jay at jay dot fm | conclude that''s because I don''t have a > > http://www.jay.fm | full grasp of the situation. - Mark Adler > > > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > Okay I don''t have any of the code on me, but you have to use a join. > This is because AR doesn''t automatically do joins for HABTM for some > reason. At first I used find_by_sql and just manually did the join, > but I''m pretty sure there''s a :join keyword that you can use to hook > it up and use within find().See the thread ''habtm example'' that I just started that addresses this problem. Somewhat.
Jay Levitt
2005-Sep-22 11:27 UTC
Re: Re: Elegant way to filter HABTM collection dynamically?
In article <c715e6405092122414377a9d1-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>, joevandyk- Re5JQEeQqe8AvxtiuMwx3w-XMD5yJDbdMReXY1tMh2IBg@public.gmane.org says...> See the thread ''habtm example'' that I just started that addresses this > problem. Somewhat.Oo! oo! Check out the CHANGELOG from EdgeRails: * Added support for calling constrained class methods on has_many and has_and_belongs_to_many collections #1764 [Tobias Luetke] class Comment < AR:B def self.search(q) find(:all, :conditions => ["body = ?", q]) end end class Post < AR:B has_many :comments end Post.find(1).comments.search(''hi'') # => SELECT * from comments WHERE post_id = 1 AND body = ''hi'' -- Jay Levitt | Wellesley, MA | I feel calm. I feel ready. I can only Faster: jay at jay dot fm | conclude that''s because I don''t have a http://www.jay.fm | full grasp of the situation. - Mark Adler