I''m just learning Rails and I''m still at the "magic happens here" stage. I''m learning db stuff too so maybe I''ve bitten off a bit too much. I have done a couple of tutorials without incident and now I''m trying to do something useful. I have struck a problem that I just haven''t been able to overcome and none of my scouring the web has revealed a solution. What I''m trying to do is create 3 objects in one form. I have a house listing object that has an image for the front of the house and an image for the inside of the house. I need to be able to identify these images as being the front and the inside for use later so I have a front_image_id key and an inside_image_id key in my listing table. In my image object I have a listing_id. In my form for entering a house listing I want the user to be able to enter the image information. It is a much better user experience if they can do this in one form rather than 3. I have created the form ok and I have even managed to create the 3 objects in the db. Where it''s coming unstuck is adding the foreign keys to the objects. The nearest I have got to a working solution is this def create @params[''front_image''][''filename''] = @params[''front_image''][''image''].original_filename.gsub(/[^a-zA-Z0-9.]/, ''_'') @params[''front_image''][''image''] = @params[''front_image''][''image''].read @params[''inside_image''][''filename''] = @params[''inside_image''][''image''].original_filename.gsub(/[^a-zA-Z0-9.]/ , ''_'') @params[''inside_image''][''image''] = @params[''inside_image''][''image''].read listing = Listing.new @params[''location''] if listing.save listing.front_image = Image.new @params[''front_image''] listing.inside_image = Image.new @params[''inside_image''] flash[''notice''] = ''Listing was successfully created.'' redirect_to :action => ''list'' else render_action ''new'' end end With this code the location_id for the inside_image gets set correctly but the front_image doesn''t (weird) and the front_image key and inside_image key in the Listing object don''t get set. Incidentally I have tried using the following in the place of the assignment, but I keep getting "no method build for nil" errors. front_image = listing.front_image.build @params[''front_image''] front_image.save It''s not surprising that the listing keys don''t get set because I''m not assigning them but it seems if I do I will need to do another listing.save which seems really inefficient. Is this the only way or am I missing some magic? Here are my models... class Listing < ActiveRecord::Base has_one :inside_image, :class_name => "Image" has_one :front_image, :class_name => "Image" end class Image < ActiveRecord::Base belongs_to :listing end Any advise on how to do this would be greatly appreciated. Henry _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
On Sun, 20 Mar 2005 00:09:56 +1300, Henry Maddocks <henryj-wUU9E3n5/m4qAMOr+u8IRA@public.gmane.org> wrote:> I''m just learning Rails and I''m still at the "magic happens here" > stage. I''m learning db stuff too so maybe I''ve bitten off a bit too > much.It can be a bit overwhelming, but stick with it, it''s not too hard to learn, and rails is totally worth the effort ;)> I have struck a problem that I just haven''t been able to overcome and > none of my scouring the web has revealed a solution. What I''m trying to > do is create 3 objects in one form. I have a house listing object that > has an image for the front of the house and an image for the inside of > the house. I need to be able to identify these images as being the > front and the inside for use later so I have a front_image_id key and > an inside_image_id key in my listing table. In my image object I have a > listing_id. In my form for entering a house listing I want the user to > be able to enter the image information. It is a much better user > experience if they can do this in one form rather than 3.Why limit yourself to just 2 images per house? What I would do is make an image model that belongs_to the house model, and say the house model has_many images. Then you can assign as many images as you want to each house, and put in whatever caption you want (to say it''s the inside, outside, whatever).> listing = Listing.new @params[''location''] > > if listing.save > listing.front_image = Image.new @params[''front_image''] > listing.inside_image = Image.new @params[''inside_image'']No surprise this doesn''t work. You''re saving to the db, then changing stuff, then not saving it. What''s wrong with this instead: listing = Listing.new @params[''location''] listing.front_image = Image.new @params[''front_image''] listing.inside_image = Image.new @params[''inside_image''] if listing.save ... ?> Incidentally I > have tried using the following in the place of the assignment, but I > keep getting "no method build for nil" errors. > > front_image = listing.front_image.build @params[''front_image''] > front_image.saveWhat? listing.front_image is nil because you haven''t created it yet, you can''t call the method "build" on a nil object. What is "build"? Is that a method in your Image class? If so, do this: listing.front_image = Image.build @params[''front_image''] listing.save -- One Guy With A Camera http://rbpark.ath.cx
On 20/03/2005, at 8:38 PM, Rob Park wrote:> On Sun, 20 Mar 2005 00:09:56 +1300, Henry Maddocks > <henryj-wUU9E3n5/m4qAMOr+u8IRA@public.gmane.org> wrote: >> I''m just learning Rails and I''m still at the "magic happens here" >> stage. I''m learning db stuff too so maybe I''ve bitten off a bit too >> much. > > It can be a bit overwhelming, but stick with it, it''s not too hard to > learn, and rails is totally worth the effort ;)I believe you. I''ve been using Ruby for years and Rails has got me excited about the web again after becoming bored with it about 6 years ago:)> Why limit yourself to just 2 images per house? What I would do is make > an image model that belongs_to the house model, and say the house > model has_many images. Then you can assign as many images as you want > to each house, and put in whatever caption you want (to say it''s the > inside, outside, whatever).I do plan to have more images but I need to be able to place the front image in a layout correctly, eg. Front image at the top off the page next to the address, then a list of the internal thumbnails below it. This is the reason I need to be able to identify the image.> >> listing = Listing.new @params[''location''] >> >> if listing.save >> listing.front_image = Image.new @params[''front_image''] >> listing.inside_image = Image.new @params[''inside_image''] > > No surprise this doesn''t work. You''re saving to the db, then changing > stuff, then not saving it. What''s wrong with this instead:According to the docs (http://rails.rubyonrails.com/classes/ActiveRecord/Associations/ ClassMethods.html) assignment contains an implicit save of the object being assigned and this does work as advertised. I found something similar in one of the tutorials that does an assignment after the save in a way which, according to the docs, shouldn''t work. (the create function on this page http://manuals.rubyonrails.com/read/chapter/51) This sent me down the wrong track for quite a while! Who do I report doc bugs to?> listing = Listing.new @params[''location''] > listing.front_image = Image.new @params[''front_image''] > listing.inside_image = Image.new @params[''inside_image''] > if listing.saveCorrect, this will work too but assigning the Image objects isn''t the problem. It''s getting their ids into the lIiting object that is causing me the headache.> >> Incidentally I >> have tried using the following in the place of the assignment, but I >> keep getting "no method build for nil" errors. >> >> front_image = listing.front_image.build @params[''front_image''] >> front_image.save > > What? listing.front_image is nil because you haven''t created it yet, > you can''t call the method "build" on a nil object. What is "build"? Is > that a method in your Image class? If so, do this:build is a function that you get when you do a belongs_to association (http://rails.rubyonrails.com/classes/ActiveRecord/Associations/ ClassMethods.html#M000338). It''s supposed to be the same as Image.new with an assignment to listing.front_image all in one call. Don''t know why it doesn''t work in this case. Anyway I''ve got something working it just seems to smell a bit... location = Location.new(@params[''location'']) old_image = Image.new @params[''old_image''] old_image.save new_image = Image.new @params[''new_image''] new_image.save location.old_image = old_image location.new_image = new_image location.old_image_id = old_image.id location.new_image_id = new_image.id if location.save flash[''notice''] = ''Location was successfully created.'' redirect_to :action => ''list'' else render_action ''new'' end With this I end up with all the keys set in the correct places. Obviously there is a bunch of error handling I need to do around the saves! Henry _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Some comments on the code I included at the end of my last message... location = Location.new(@params[''location'']) old_image = Image.new @params[''old_image''] old_image.save new_image = Image.new @params[''new_image''] new_image.save location.old_image = old_image location.new_image = new_image location.old_image_id = old_image.id location.new_image_id = new_image.id if location.save flash[''notice''] = ''Location was successfully created.'' redirect_to :action => ''list'' else render_action ''new'' end According to the docs for has_one an assignment automatically saves the object being assigned, so this statement location.old_image = old_image is doing a save. This is in fact the case because the row appears in my table. So this would mean that the explicit saves that I''m doing are redundant... old_image = Image.new @params[''old_image''] old_image.save But, if I don''t do this the value of old_image.id is nil and the assignment location.old_image_id = old_image.id fails which is a bad thing. It appears that the db is being updated but the object''s members aren''t. As I said still at the "magic happens here" stage waiting for an epiphany. Tomorrow I will trace the code, now though, it''s time for bed. Henry _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails