Now I warned you, here’s the problem that’s been getting me mad for hours
I’ve got a model for content I’m calling “lead”. It has a title, a text and an image used as a background.
I’m not using paperclip or CarrierWave to handle the image file (and I don’t want to, one of my needs here is to learn how this all works).
I’m using this function to upload the file (it comes directly from the rails guides) :
def upload
if params[:lead][:illustration]
uploaded_io = params[:lead][:illustration]
File.open(Rails.root.join('app', 'assets', 'images', uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
end
@lead.illustration = "#{uploaded_io.original_filename}"
end
end
When creating a “lead”, everything goes fine with create:
def create
@lead = Lead.new( params[:lead] )
upload
if @lead.save
flash[:success] = "Lead successfully added."
redirect_to @lead
else
redirect_to root_path
end
end
The “lead” gets saved, I can use it. So far, so good.
Now with the problem (remember the NOOB ALERT).
Updating a lead without modifying the image goes fine, but updating with a new image returns this error:
Now I warned you, here's the problem that's been getting me mad for hours
I've got a model for content I'm calling "lead". It has a title, a text and
an image used as a background.
I'm not using paperclip or CarrierWave to handle the image file (and I don't
want to, one of my needs here is to learn how this all works).
I'm using this function to upload the file (it comes directly from the rails
guides) :
def upload
if params[:lead][:illustration]
uploaded_io = params[:lead][:illustration]
File.open(Rails.root.join('app', 'assets', 'images',
uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
end
@lead.illustration = "#{uploaded_io.original_filename}"
end
end
When creating a "lead", everything goes fine with create:
def create
@lead = Lead.new( params[:lead] )
upload
if @lead.save
flash[:success] = "Lead successfully added."
redirect_to @lead
else
redirect_to root_path
end
end
The "lead" gets saved, I can use it. So far, so good.
Now with the problem (remember the NOOB ALERT).
Updating a lead without modifying the image goes fine, but updating with a
new image returns this error:
The error says that you are calling method 'name' for something that
is nil at line 45 in leads_controller.rb.
Here's my update function:
def update
@lead = Lead.find_by_id( params[:id] )
upload
if @lead.update_attributes!(params[:lead])
flash[:success] = "Leaderboard successfully updated."
redirect_to @lead
else
render action: "edit"
end
end
Basically the same as create. I've been googling and going back and forth
for hours and I didn't get to solve this. Any help would be more than
welcome.
Unfortunately you have not told us which is line 45.
It is also better not to use html as now the fact that you highlighted
the line above is not visible.
Have you checked that @lead is not nil?
Have a look at the Rails Guide on Debugging to get lots of ideas on
how to debug your code. Start by looking in log/development.log to
check that the attributes are being passed correctly. Then, for
example, use the debugger to break into the code and check what is
going on or put diagnostic puts statements in to inspect the data.
> ...
> Thanks for the advise. Logging led me to a solution, but I don't
> really understand what's going on under the hood.
>
> Here's my solution:
>
> "upload" now returns this:
> return "#{uploaded_io.original_filename}"
>
> In "create", I set:
> @lead.illustration = upload
>
> In "update", this wont work. I need to set:
> params[:lead][:illustration] = upload
> and the update goes fine.
>
> After finding this out I tried to set
> params[:lead][:illustration] = upload
> instead of
> @lead.illustration = upload
> in "create", and that wont work.
Can you post your create and update methods as you now have them so I
can see what you are doing.
Sure, here goes :
def create
@lead = Lead.new( params[:lead] )
@lead.illustration = upload_image
if @lead.save
flash[:success] = "Leaderboard successfully added."
redirect_to @lead
else
redirect_to root_path
end
end
def update
@lead = Lead.find_by_id( params[:id] )
params[:lead][:illustration] = upload_image
You said that doing @lead.illustration = upload_image (presumably at
this point) did not work. It should do, provided that
params[:lead][:illustration] is not present. If it is then the value
from upload_image will be overwritten by the value from params when
you call update_attributes. Another possibility is that if the
illustration is the only field being changed then update_attributes
may not actually save the record (as it does not think anything has
changed).
Probably leaving it as you have it is the simplest solution.
...
Thanks for the advise. Logging led me to a solution, but I don't
really understand what's going on under the hood.
Here's my solution:
"upload" now returns this:
return "#{uploaded_io.original_filename}"
In "create", I set:
@lead.illustration = upload
In "update", this wont work. I need to set:
params[:lead][:illustration] = upload
and the update goes fine.
After finding this out I tried to set
params[:lead][:illustration] = upload
instead of
@lead.illustration = upload
in "create", and that wont work.
Can you post your create and update methods as you now have them so I
can see what you are doing.
Sure, here goes :
def create
@lead = Lead.new( params[:lead] )
@lead.illustration = upload_image
if @lead.save
flash[:success] = "Leaderboard successfully added."
redirect_to @lead
else
redirect_to root_path
end
end
def update
@lead = Lead.find_by_id( params[:id] )
params[:lead][:illustration] = upload_image
You said that doing @lead.illustration = upload_image (presumably at
this point) did not work. It should do, provided that
params[:lead][:illustration] is not present. If it is then the value
from upload_image will be overwritten by the value from params when
you call update_attributes. Another possibility is that if the
illustration is the only field being changed then update_attributes
may not actually save the record (as it does not think anything has
changed).
Probably leaving it as you have it is the simplest solution.
Colin
Jean-David,
Here's a bit of code from an old project of mine:
def update
data = params[:product].delete('data') # HashWithIndifferentAccess still needs the actual key type to .delete
begin
@product = Product.find(params[:id], :conditions => { :virtual => true })
unless data.blank? # i.e., not replacing image
content = data.read
if content.blank?
flash[:error] = "Selected upload file was empty"
redirect_to :action => 'edit'
return
end
@product.image_size = ImageSizer.of_blob(content).size
filename = Product.get_local_image_name data.original_filename
File.open(File.join(RAILS_ROOT, 'public', filename), 'wb') do |f|
f.write content
end
@product.image = filename
end
respond_to do |format|
if @product.update_attributes(params[:product])
…
end
Note that I am removing the 'data' key from the attributes hash params[:product] so that it isn't used in the .update_attributes call later. Perhaps you need to remove the 'illustration' since you've already handled that portion of the update.
If you know that the illustration is changed, but ActiveRecord doesn't, then perhaps you need to call @lead.illustration_will_change! to inform AR that the attribute is dirty and needs to be written out.
You said that doing @lead.illustration = upload_image (presumably at
this point) did not work. It should do, provided that
params[:lead][:illustration] is not present. If it is then the value
from upload_image will be overwritten by the value from params when
you call update_attributes. Another possibility is that if the
illustration is the only field being changed then update_attributes
may not actually save the record (as it does not think anything has
changed).
Probably leaving it as you have it is the simplest solution.
Colin
Jean-David,
Here’s a bit of code from an old project of mine:
def update
data = params[:product].delete('data') # HashWithIndifferentAccess still needs the actual key type to .delete
begin
@product = Product.find(params[:id], :conditions => { :virtual => true })
unless data.blank? # i.e., not replacing image
content = data.read
if content.blank?
flash[:error] = "Selected upload file was empty"
redirect_to :action => 'edit'
return
end
@product.image_size = ImageSizer.of_blob(content).size
filename = Product.get_local_image_name data.original_filename
File.open(File.join(RAILS_ROOT, 'public', filename), 'wb') do |f|
f.write content
end
@product.image = filename
end
respond_to do |format|
if @product.update_attributes(params[:product])
…
end
Note that I am removing the ‘data’ key from the attributes hash params[:product] so that it isn’t used in the .update_attributes call later. Perhaps you need to remove the ‘illustration’ since you’ve already handled that portion of the update.
If you know that the illustration is changed, but ActiveRecord doesn’t, then perhaps you need to call @lead.illustration_will_change! to inform AR that the attribute is dirty and needs to be written out.
-Rob
Thank you Rob, I’ll try to put that in my own sauce (that’s an approximate translation for french “à ma sauce” ; )