Reputation: 4097
I am trying to create an upload form that allows the user to select a blank value which will then result in another upload process. ( I substituted in "class" for my actual class name).
My upload form is
<%= form_for @upload, :url => class_uploads_path(@uploader), :method =>
:post, :html =>{ :multipart => true } do |f| %>
<%= render "shared/error_messages", :target => @upload %>
<p>This media relates to...<br/>
<%= select "upload", "class_id", Class.all.collect {|class| [class.name,class.id] }, {
:include_blank => true } %></p>
<p>Title:<br/>
<%= f.text_field :title %></p>
<p>Description:<br/>
<%= f.text_area :description, :rows => 3 %></p>
<p>File to upload:<br/>
<%= f.file_field :data %></p>
<p><%= f.submit 'Upload for review' %></p>
<% end %>
Here is my create method, if the user leaves the select form blank I would like the first upload action to run and if they chose a class I want the second upload to run.
def create
upload_params = params[:upload] || params[:image] || params[:video]
@class = Class.find(upload_params[:class_id]) || nil
begin
if upload_params[:data]
file_name = upload_params[:data].original_filename
file_contents = upload_params[:data].read
end
rescue
@upload = Upload.new
flash[:error] = "Could not find upload file data. Please reselect file."
render :action => 'new' and return
end
begin
if @class.nil?
@upload = Upload.factory({ :file => file_contents,
:name => file_name,
:network => @uploader,
:title => upload_params[:title],
:description => upload_params[:description] })
else
@upload = Upload.factory({ :file => file_contents,
:name => file_name,
:class => @class,
:network => @uploader,
:title => upload_params[:title],
:description => upload_params[:description] })
end
@upload.save!
I have tried a number of different hacks, I am trying to avoid adding a new column to the database. Thanks in advance.
Upvotes: 0
Views: 318
Reputation: 30485
Kyle, if the blank option is chosen, I believe params[:class_id] should be "" (a blank string). You should check this -- look in your development logs and see what params are getting passed back to your controller method, both when you select a class and when you don't.
If that is correct:
class_id = params[:class_id]
@class = Class.find(class_id.to_i) if class_id and not class_id.empty?
As gg_s pointed out, there is lots of room for refactoring the code you posted. But if you just want to get the existing code working, this might be helpful.
In future, when something is not working, rather than just "hacking on it until it works", look at the logs/console output for more information. Add logging statements to the controller method, printing out the values of variables, etc. Then try it out, and look at the logs again to see what is happening inside the method.
Upvotes: 1
Reputation: 6682
If the only difference between both uploads is a :class => @class
pair, there should be no reason to have two separate actions.
I assume the following:
Upload
objects here (upload.rb
model, uploads_controller.rb
controller)Upload.factory
is a processor method which handles and formats upload data, resulting in a complete Upload
object with a file and metadata.If so, all of that controller logic can be moved to the model. Pass data to the model with instance variables (via attr_accessor
, not by adding columns). Slap a before_create
filter on factory
so it processes your upload before saving.
Use validations to handle "no data" errors.
Here's an example. upload.rb
:
before_create :factory # run your factory method before creating
attr_accessor :form_data, :form_network, :form_title, \ # settable from controller
:form_description, :form_class_id
validates :form_data, :presence => true, :on => :create, \ # fail if no data
:message => "No file data. Please reselect file."
private
def factory
file_name = self.form_data.original_filename
file_contents = self.form_data.read
class = Class.where(:id => self.form_class_id).first # returns Class or nil
# if class is nil, handle it however you need to here
# access self.form_network, self.form_title, self.form_description directly
# ... factory magic ...
end
Now your controller can be as tidy as this:
def create
upload_params = params[:upload] || params[:image] || params[:video]
@upload = Upload.new({ :form_data => upload_params[:data],
:form_network => @uploader, # <-- undefined!
:form_class_id => upload_params[:class_id],
:form_title => upload_params[:title],
:form_description => upload_params[:description]})
if @upload.save
redirect_to @upload
else
render :action => "new"
end
end
Note that @uploader
is undefined.
@upload.save
will validate the @upload
. If file data is absent, save
will fail, kicking you back to the new
action with a "no data" error message. Otherwise, if validation passes, factory
is called, then the record saves.
Upvotes: 0