Rails form file upload newbie issue - ruby-on-rails

I have an issue retrieving my file upload information. I am just starting to learn Rails.
I am using ruby 2.0.0p0
And Rails 4.0.0.beta1
Here is my form:
<%= form_for(#person, :html => { :multipart => true }) do |f| %>
<div class="field">
<%= f.label :photo %><br />
<%= f.file_field :photo %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And in my person.rb model:
def photo=(file_data)
logger.debug("PHOTO")
logger.debug(file_data)
logger.debug("END OUTPUT PHOTO")
unless file_data.blank?
#file_data = file_data
self.extension = file_data.original_filename.split('.').last.downcase
end
end
I can see in my console that nothing happens (no "PHOTO" output), the photo method is never called.
Why is that?
When I looked in the console I also saw this line that got me worried:
Unpermitted parameters: photo
What does that mean?

In your controller, where you're dealing with params, you need to use .permit to list the attributes the form is allowed to post:
#person = Person.new(params.require(:person).permit(:photo))
Alternatively, if you used Rails' scaffolding generator, you might instead have a person_params method where you would need to add the :photo attribute:
def person_params
params.require(:person).permit(:photo, :name, etc...)
end

Related

Why does Rails form multiple: true change submitted param form

I'm playing with ActiveStorage and trying to upload some files locally. Everything works great with the code below, but only if I remove multiple: true from the form. When it is on the form, I get an unpermitted param "files" error in the console. The unpermitted param comes from the way the form is submitting the hash.
Without multiple: true the hash lists attachments as an array (this is the working version):
"article"=>{"files"=>[#<ActionDispatch::Http::UploadedFile:0x007fb4e8e287f0
But with it turned on it it removes the array:
"article"=>{"files"=>#<ActionDispatch::Http::UploadedFile:0x007fb4eb07b7d0
What is causing this form behavior and how can I fix it?
I got the code sample from Engine Yard and here is the project code:
<h3>Attach files to this post</h3>
<%= form_with model: #article, local: true do |f| %>
<div class="form-row">
<%= f.label :file_upload, 'Attach a file' %>
<%= f.file_field :files, multiple: true %>
</div>
<%= f.submit %>
<% end %>
<h3>Attached files</h3>
<% #article.files.each do |file| %>
<%= link_to file.blob.filename, url_for(file) %>
<% end %>
When you use multiple: true you need to permit an array explicit in the article_params for :files:
For example:
params.require(:article).permit(:author, :text, files: [])
You can read more under Action Controller
Good luck!

RoR : Mongoid and form create hash

Simple question for Rails gurus. Why I do have to use the following statement to insert a new Mongoid document : params[:video][:description] in the following create method of my VideosController? Why I can't use the params[:description] from the POST form? If I use it, the value becomes nil.
def create
#video = Video.new(
:title => params[:video][:title],
:description => params[:video][:description]
)
if #video.save
render 'success'
else
render 'error'
end
end
Here is the Video.rb class :
class Video
include Mongoid::Document
field :title, type: String
field :description, type: String
validates_presence_of :title
validates_presence_of :description
acts_as_url :title
end
And finaly the form view :
<%= form_for #video do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<p/>
<%= f.label :description %>
<%= f.text_field :description %>
<%= submit_tag("Enqueue video") %>
<% end %>
I don't quite get why the form input are video[description] and not just description as expected :
<label for="video_title">Title</label>
<input id="video_title" name="video[title]" type="text" />
<p/>
<label for="video_description">Description</label>
<input id="video_description" name="video[description]" type="text" />
When you are using form_for:
Creates a form that allows the user to create or update the attributes
of a specific model object.
In your case, Video model. To understand Rails convention:
<%= form_for #video do |f| %>
...
<%= f.text_field :description %>
...
Which results in an html tag whose name attribute is video[description]. This means that when the form is submitted, the value entered by the user will be available in the controller as params[:video][:description].
The params variable is an instace of ActiveSupport::HashWithIndifferentAccess, like a Hash with a small difference, according to documentation:
This class has dubious semantics and we only have it so that people
can write params[:key] instead of params[‘key’] and they get the same
value for both keys.
Your params is something like:
{"utf8"=>"✓",
"_method"=>"post",
"authenticity_token"=>"xxx",
"video"=>
{"description"=>"Video desc"}
}
Where "video" or :video is one of the keys of the Hash. So, params[:video] is equivalent to params.fetch("video") which value is {"description"=>"Video desc"}. As you can see the value is another Hash. Finally to get the value of the description you have to params[:video][:description] (The Rails way) or params.fetch("video").fetch("description"), which value is "Video desc".
fetch is a Ruby method of Hash: "Returns a value from the hash for the given key."
Taking this into account:
Video.new(params[:video]) = Video.new(:description => "Video desc") = Video.new(:description => params[:video][:description])
It's easier to use conventions, but for sure you can have params[:description] (just in case):
<%= form_for #video do |f| %>
...
<%= text_field_tag :description %>
...
Note that I'm using text_field_tag instead of f.text_field. In this case the html tag name will be description in the params Hash you will receive { "description" => 'Video desc" }...
Take a look to Rails API documentation to understand different helpers, etc. And also review your server's log.
If you want to use video[:description]. Create your form like this
<%= form_for #video do |f| %>
....
<p/>
<%= f.label :description %>
<%= f.text_field :description, :name => "description" %>
....
<% end %>
Rails form_for helper name the input elements such that it becomes easy to push them into model attributes in one go like this
#video = Video.new(params[:video])
so that you don't have to do it like the way you have done
#video = Video.new(
:title => params[:video][:title],
:description => params[:video][:description]
)

rails carrierwave edit/update form

In my rails project I use Carrierwave to upload images to S3 via fog. So far I have the Create Read and Delete portions of the CRUD spectrum working.
My problem is the edit/update portion. Im use the same _form.html.erb to edit that I used for creating records. When I click the edit link the form loads all of my data into the form fields for editing with the exception of the image. The form field is blank as though there is no image associated with the record.
How do I update an image that is already saved to S3?
Models/listing.rb
class Listing < ActiveRecord::Base
attr_accessible :body, :price, :title, :image
mount_uploader :image, ListingUploader
end
Controllers/listings_controller.rb (edit/update portion)
def edit
#listing = Listing.find(params[:id])
end
def update
#listing = Listing.find(params[:id])
if #listing.update_attributes(params [:listing])
redirect_to :action => 'show', :id => #listing
else
render :action => 'edit'
end
end
_form.html.erb
<%= form_for #listing, :html => { :multipart => true } do |l| %>
<p>
<%= l.label :title %>
<%= l.text_field :title %>
</p>
<p>
<%= l.label :price %>
<%= l.text_field :price %>
</p>
<p>
<label>Upload a Picture</label>
<%= l.file_field :image %>
<%= l.hidden_field :image_cache %>
</p>
<div class="image-pre">
<%= image_tag(#listing.image_url(:thumb)) if #listing.image? %>
</div>
<p>
<%= l.label :body %>
<%= l.text_area :body, :class => "tinymce" %>
<%= tinymce %>
</p>
<%= l.submit %>
<% end %>
In your listings_controller.rb, try something like:
def edit
#listing = Listing.find(params[:id])
#listing.image.cache!
end
Haven't tested this out myself, but I think it might work, given that image_cache field is used to circumvent this problem normally.
I had upgraded my app to Rails 6 sometime ago, then started experiencing this issue.
tldr; you need a carrierwave gem version 2.1.0 or higher for Rails 5.0 and up.
I used bundle outdated --strict to see if carrierwave could be upgraded. Check Gemfile to see if the requested version is set correctly. Also check Gemfile.lock to see if other gems are holding it back; you'll need to upgrade them as well. Then I used bundle update --strict to perform the actual upgrade.

Ruby On Rails: example of file_field on form_for

I came across file uploading problem in Rails. I found file_field :file helper, that can be used with form_for(#some_model). However, I cannot find any usage for this case, as those tags are used to create/edit some model, by mass assigning. There is, AFAIK, no possibility to treat fileupload as typical field ( See File upload won't work in Ruby on Rails 3 using Multipart Form ). In such a case, manual operation on uploaded file is required. So, why would someone even want to puts a fileupload as a part of model editing?
photo.rb
class Photo < ActiveRecord::Base
attr_accessible :name, :filename,
end
photo_form.html.erb
<%= form_for(#photo, :multipart => true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.file_field :file %>
<%= f.submit %>
<% end %>
photos_controller.rb
def create
#photo = Photo.new(params[:photo])
line above fails, because theres no :file attribute. It must be handled before and manually removed from :params. Once more - is there any real usage for such tags?
I will will you an example how I am using it I think it explains itself good enough, I hope this helps
<%= form_for #item do |f|%>
<%= f.file_field :photo, accept: 'image/png,image/jpeg'%>
<% end %>
Let me know if you have any doubts
I remember that I used this to upload a xml file in Rails
view:
<%= form_tag({action: :upload}, multipart: true) do %>
<%= file_field_tag 'xml_file' %>
<%= submit_tag 'Submit' %>
<% end %>
controller:
def upload
file_data = params[:xml_file]
end
It is using form_tag but it would not be hard to add other info into that form also.

Rails 3 Form File Handling Question

I have a Rails 3 application with a pretty standard multipart form that includes an image upload. However, it throws an error.
The form starts with:
<%= form_for(#object, :html => { :multipart => true }) do |f| %>
<div class="field">
<%= f.label :photo %>
<%= f.file_field :photo %>
</div>
<div class="actions">
<%= f.submit 'Submit Object' %>
</div>
<% end %>
Then, I have this in the object.rb model:
def photo=(file_data)
unless file_data.blank
#file_data = file_data
self.extension = file_data.original_filename.split('.').last.downcase
end
end
This throws the following error:
undefined method `blank' for #ActionDispatch::Http::UploadedFile:0x37ecc78
Meanwhile, it also shows the image exists in the Request Parameters error page:
"photo"=>#ActionDispatch::Http::UploadedFile:0x37ecc78 #original_filename="Image.jpg",
Any help would be greatly appreciated!
The blank method doesn't exist. It's blank?, with the question mark.
unless file_data.blank?
...
Documentation

Resources