I’m very new to Rails, so it’s likely there’s a simple concept here that I’m just not getting, but here’s what’s happening.
I have a User model (powered by Devise), and each user has it’s own respective photo attribute. I know I could have included the photo as part of the User, but the photos are actually the core content of the site, so I preferred them to be their own table. The photo model has a paperclip attachment which handles the actual photo file.
Here’s the issue: Everything works according to plan when I upload a photo as a user, but for some reason, when I return to the photo upload page, the photo I just uploaded gets deleted. I’ve tracked it down to this line of code:
@photo = @user.build_photo
If I don’t call that, the form for the upload throws a nil class error because @user.photo doesn’t exist, but when I DO call it, it deletes the previously uploaded photo, which is weird, because as far as I know, it’s the create function that alters the database, not the build.
Here’s what the server shows:
Started GET “/settings” for 127.0.0.1 at 2012-03-08 10:19:21 -0800
Processing by SettingsController#index as HTML User Load (0.3ms)
SELECTusers.* FROMusersWHEREusers.id= 6 LIMIT 1 Photo
Load (0.3ms) SELECTphotos.* FROMphotosWHEREphotos.user_id
= 6 LIMIT 1 (0.2ms) BEGIN [paperclip] Scheduling attachments for deletion. SQL (0.6ms) DELETE FROMphotosWHEREphotos.id= 20
[paperclip] Deleting attachments.
And here’s a couple of my models and controllers:
class SettingsController < ApplicationController
def index
@user = current_user
@photo = @user.build_photo
end
end
<h1>Settings Page</h2>
<%= image_tag @user.photo.the_photo.url(:medium) %>
<%= form_for [@user, @photo], :html => { :multipart => true } do |f| %>
<%= f.file_field :the_photo %>
<%= f.submit %>
<% end %>
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :photo_attribute
has_one :photo, :dependent => :destroy
accepts_nested_attributes_for :photo
end
class PhotosController < ApplicationController
def create
@user = current_user
@photo = @user.create_photo(params[:photo])
redirect_to root_path
end
def update
@user = current_user
@photo = @user.photo
if @photo.update_attributes(params[:photo])
redirect_to settings_path
else
redirect_to settings_path
end
end
def destroy
end
end
As you’ve discovered, calling
@user.build_photowill remove aphotofor thatuserif one already exists. You just need to skip doing thebuildin that case: