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