I''m thoroughly enjoying spending some time delving deeper into the world of Rails and really enjoying discovering all the in-built features. However, I''m coming a bit unstuck when working with Associations and particularly when using models with has_and_belongs_to_many. I''ve got two classes setup and compiling fine, along with the relevant join table, and I''m able to access the collection and collection attributes. I''m unsure though how I should implement the form view (I''d like either a series of standard select fields, or just one multiple select field) and then process the update to the collection through the controller. Appears that just using a standard Object.new gives me an AssociationTypeMismatch error when I invoke the ''new'' method. I''ve seen a few examples of ways around this, but would like some advice on the most graceful and simple method. Below are some snippets from my code: from _form.rhtml <p><label for="cocktail_ingredients">Ingredients</label><br/> <%= select("cocktail", "ingredients", Ingredient.find_all.collect {|i| [ i.name, i.id ] }, :include_blank => true) %></p> from cocktails_controller.tb def new @cocktail = Cocktail.new end -Phil
> However, I''m coming a bit unstuck when working with Associations and > particularly when using models with has_and_belongs_to_many.I''m looking for some guidance on habtm as well. In particular, I am confused as to how one would go about editing the relationship. For example ... lets say we have the models Book and Author. A book can have multiple authors, and authors have multiple books, so we have our habtm. Lets say we have a book with 2 authors. Agile Web Development with Rails <----> Dave Thomas Agile Web Development with Rails <----> Joe Bob Oops! Joe Bob is not an author of AWDwR. We need to change that so that it points to another author - DHH. Now, with a belongs_to relationship in Book, we would just have to change Book.author_id, like this: book = Book.find( 1 ) book.author_id = 2 book.save But how would you do something similar with a habtm relationship?
> I''m looking for some guidance on habtm as well. In particular, I am > confused as to how one would go about editing the relationship. For > example ... lets say we have the models Book and Author. A book can > have multiple authors, and authors have multiple books, so we have our > habtm. Lets say we have a book with 2 authors. > > Agile Web Development with Rails <----> Dave Thomas > Agile Web Development with Rails <----> Joe Bob > > Oops! Joe Bob is not an author of AWDwR. We need to change that so > that it points to another author - DHH. > > Now, with a belongs_to relationship in Book, we would just have to > change Book.author_id, like this: > > book = Book.find( 1 ) > book.author_id = 2 > book.save > > But how would you do something similar with a habtm relationship?book.authors.delete(@joebob) book.authors << @dhh -- rick http://techno-weenie.net
> from _form.rhtml > > <p><label for="cocktail_ingredients">Ingredients</label><br/> > <%= select("cocktail", "ingredients", Ingredient.find_all.collect {|i| > [ i.name, i.id ] }, :include_blank => true) %></p> > > from cocktails_controller.tb > > def new > @cocktail = Cocktail.new > endDoes it give you an AssociationTypeMismatch when you try to instantiate the create the object? @cocktail = Cocktail.new @params[:cocktail] I think it''s because it''s then trying to set @cocktail.ingredients @params[:cocktail][:ingredients]. Maybe there''s a way for this to work, but I just use a totally different parameter name. This code is off the top fo my head, so I''ll probably get some syntax errors. <%= select_tag ''ingredients'', @ingredients.collect { |i| [i.name, i.id] } %> Then in the controller: @cocktail = Cocktail.new @params[:cocktail] @cocktail.ingredients << Ingredient.new(@params[:ingredients]) -- rick http://techno-weenie.net
Belorion <belorion-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:> Oops! Joe Bob is not an author of AWDwR. We need to change that so > that it points to another author - DHH. > > Now, with a belongs_to relationship in Book, we would just have to > change Book.author_id, like this: > > book = Book.find( 1 ) > book.author_id = 2 > book.save > > But how would you do something similar with a habtm relationship?My understanding is the you need to delete and re-add book = Book.find(1) book.authors.delete(Author.find_by_name("Joe Bob")) book.authors << Author.find_by_name("DHH") This assumes you don''t want to actually delete "Joe Bob" from authors table and "DHH" already has an entry. If you just misspelled "Joe Bob" and want to update that, then just find the Author and change his name. -- doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
Phil Powell <phil-ldtTreVRrIMcWVvVuXF20w@public.gmane.org> writes:> I''m unsure though how I should implement the form view (I''d like either > a series of standard select fields, or just one multiple select field) > and then process the update to the collection through the controller. > Appears that just using a standard Object.new gives me an > AssociationTypeMismatch error when I invoke the ''new'' method. > > I''ve seen a few examples of ways around this, but would like some > advice on the most graceful and simple method.There''s been some discussion around this with respect to check boxes: http://wiki.rubyonrails.com/rails/show/HowToUseCheckBoxes Too bad you can''t search the mailing list archives for a thread we had on this about three weeks ago. The short story is that there''s not much hand-holding to handle it, but Ruby can help. -- doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
On 6/3/05, Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > from _form.rhtml > > > > <p><label for="cocktail_ingredients">Ingredients</label><br/> > > <%= select("cocktail", "ingredients", Ingredient.find_all.collect {|i| > > [ i.name, i.id ] }, :include_blank => true) %></p> > > > > from cocktails_controller.tb > > > > def new > > @cocktail = Cocktail.new > > end > > Does it give you an AssociationTypeMismatch when you try to > instantiate the create the object? > > @cocktail = Cocktail.new @params[:cocktail] > > I think it''s because it''s then trying to set @cocktail.ingredients > @params[:cocktail][:ingredients]. Maybe there''s a way for this to > work, but I just use a totally different parameter name. > > This code is off the top fo my head, so I''ll probably get some syntax errors. > <%= select_tag ''ingredients'', @ingredients.collect { |i| [i.name, i.id] } %> > > Then in the controller: > @cocktail = Cocktail.new @params[:cocktail] > @cocktail.ingredients << Ingredient.new(@params[:ingredients])I was involved in a thread a little bit ago that addressed this. Check the archives. Add a ingredients= method to the Cocktail model that that removes the associated Cocktail''s ingredients and then adds the new ingredients in. Then, your view can have checkboxes like "cocktail[ingreidents][1]" where 1 is the id of an ingredient. Bonus points if you do some metaprogramming that adds in the method ingredients= if you do: habtm_setter :ingredients in the Cocktail model.
> Add a ingredients= method to the Cocktail model that that removes the > associated Cocktail''s ingredients and then adds the new ingredients > in. Then, your view can have checkboxes like > "cocktail[ingreidents][1]" where 1 is the id of an ingredient. > > Bonus points if you do some metaprogramming that adds in the method > ingredients= if you do: > > habtm_setter :ingredients > > in the Cocktail model.That''s actually not a bad idea! I may look into that.... rick
On 6/3/05, Doug Alcorn <doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org> wrote:> Phil Powell <phil-ldtTreVRrIMcWVvVuXF20w@public.gmane.org> writes: > > > I''m unsure though how I should implement the form view (I''d like either > > a series of standard select fields, or just one multiple select field) > > and then process the update to the collection through the controller. > > Appears that just using a standard Object.new gives me an > > AssociationTypeMismatch error when I invoke the ''new'' method. > > > > I''ve seen a few examples of ways around this, but would like some > > advice on the most graceful and simple method. > > There''s been some discussion around this with respect to check boxes: > > http://wiki.rubyonrails.com/rails/show/HowToUseCheckBoxes > > Too bad you can''t search the mailing list archives for a thread we had > on this about three weeks ago. The short story is that there''s not > much hand-holding to handle it, but Ruby can help.Why can''t you? I can. :-) http://thread.gmane.org/gmane.comp.lang.ruby.rails/10221 There''s the link that should answer the OP''s question.
Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:>> Too bad you can''t search the mailing list archives for a thread we had >> on this about three weeks ago. The short story is that there''s not >> much hand-holding to handle it, but Ruby can help. > > Why can''t you? I can. :-) > > http://thread.gmane.org/gmane.comp.lang.ruby.rails/10221I tried to start another thread about this elsewhere. Is gmane our official mailing list archive? If so, we should update Mailman so that''s in the headers. Personally, I feel like our mailing list archives are mostly broke. -- doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
On 6/3/05, Doug Alcorn <doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org> wrote:> Joe Van Dyk <joevandyk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes: > > >> Too bad you can''t search the mailing list archives for a thread we had > >> on this about three weeks ago. The short story is that there''s not > >> much hand-holding to handle it, but Ruby can help. > > > > Why can''t you? I can. :-) > > > > http://thread.gmane.org/gmane.comp.lang.ruby.rails/10221 > > I tried to start another thread about this elsewhere. Is gmane our > official mailing list archive? If so, we should update Mailman so > that''s in the headers. Personally, I feel like our mailing list > archives are mostly broke.I didn''t know we had an official mailing list archive... but yeah, probably should use gmane. Although, using gmail gives me an awesome searchable archive of all the mailing lists that I''m subscribed to as well. And since storage space always increases... probably won''t run out of space anytime soon. :-)