I'm working on a project that requires an ActiveStorage has_many_attached :photos situation on a Location model.
I have the code set up below, but when attempting to upload a form, I receive the following error:
ActiveSupport::MessageVerifier::InvalidSignature in
LocationsController#attach_photo
Is this the way to "add" a file to the set of attachments for a particular parent record (i.e: a Location record)?
Location Model
class Location < ApplicationRecord
...
has_many_attached :photos
...
end
Locations Controller
class LocationsController < ApplicationController
...
def attach_photo
#location = Location.find(params[:id])
#location.photos.attach(params[:photo])
redirect_to location_path(#location)
end
...
end
View
<%= form_tag attach_photo_location_path(#location) do %>
<%= label_tag :photo %>
<%= file_field_tag :photo %>
<%= submit_tag "Upload" %>
<% end %>
View
resources :locations do
member do
post :attach_photo
end
end
Make sure to add multipart: true in form_tag. It generates enctype="multipart/form-data".
form_tag by default not responsible for it, must have it (if attaching a file).
multipart/form-data No characters are encoded. This value is required
when you are using forms that have a file upload control
Form:
<%= form_tag attach_photo_location_path(#location), method: :put, multipart: true do %>
<%= label_tag :photo %>
<%= file_field_tag :photo %>
<%= submit_tag "Upload" %>
<% end %>
Also:
Change post to put method, We are updating not creating Idempotency
resources :locations do
member do
put :attach_photo
end
end
You need to assign the signature (in params[:signed_blob_id]) to the instance as the example from the docs illustrates.
So, like this:
#location.photos.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
I solved this issue using this
def user_params
params.permit(
:id, :name, :email, :username, :country, :avatar, :id_number, :license_number
).select {|x,v| v.present?}
end
Looks like the empty value is causing the issue "avatar"=>""
"id_number"=>"234545", "license_number"=>"234545", "avatar"=>""
My model
class User < ApplicationRecord
has_one_attached :avatar
Rails Active Storage + React Native + React Native debugger with Network Inspect Enabled may cause this error.
If you're using React Native debugger with Network Inspect Enabled, file uploading might not be working because of this known issue: Formdata sends [object object] in request.
Turn off Network Inspect when you're using React Native debugger. You can inspect network payload with Reactotron instead.
Related
I have a form for a blog, and I would like to have two field for images. One image being the cover (in Show) and another image will serve as a preview (in index).
My form looks as follow:
<%= semantic_form_for #blog, :html => { :multipart => true } do |f| %>
<%= t :Choose_File_for_cover %> <%= f.file_field :image_path, id: "avatar-upload2", required: true %>
<img id="img_prev3" width="100%" height=200 src="#" alt="your image" class="img-thumbnail hidden"/>
<%= t :Choose_File_for_homepage %> <%= f.file_field :homepagepic, id: "avatar-upload3", required: true %>
<%= f.hidden_field :image_path_cache %>
<%= f.hidden_field :homepagepic_cache %>
<%= f.actions do %>
<%= f.action :submit, :as => :input %>
<% end %>
<% end %>
My model looks like:
class Blog < ApplicationRecord
belongs_to :user
acts_as_taggable
mount_uploader :image_path, BlogUploader
mount_uploader :homepagepic, BlogcoverUploader
end
It works well when I only have the image_path (the cover), but when I add a new field for homepagepic, i get a ROLLBACK at validation.
Can someone help me on how to select files through two separate fields on the same form please.
Thank you
The code you've provided is very sparse and it would be helpful to see a little bit more (e.g. the controller and the uploader).
I can, however, hazard a guess: image_path is an existing helper method provided by Rails (see https://api.rubyonrails.org/classes/ActionView/Helpers/AssetUrlHelper.html#method-i-image_path). I have absolutely no idea what happens when you use this as a name for a form field. It could also be because you declare your submit button to be an input (I've only ever seen and used as: :button for f.action :submit).
So overall, I would pick the following approach:
rename your upload fields to cover_image and the other one to preview_image (that's what you've described in your posts as their respective purpose, so you should name them accordingly)
change the submit to a button and remove all the noise from your template and start with the bare minimum: the two upload fields and nothing else (see sample code below – note that I haven't tested it but it should work or be very close to working)
after that works, start adding back the noise (i.e. the translations, the cache fields etc.)
Test that it still works after every step. If you can write a Capybara test, do that – otherwise test it manually.
If you have questions, feel free to ask.
<%= semantic_form_for #blog, html: { multipart: true } do |f| %>
<%= f.file_field :cover_image %>
<%= f.file_field :preview_image %>
<%= f.actions do %>
<%= f.action :submit, as: :button %>
<% end %>
<% end %>
class Blog < ApplicationRecord
belongs_to :user
acts_as_taggable
mount_uploader :preview_image, BlogUploader
mount_uploader :cover_image, BlogcoverUploader
end
As the previous poster said it's hard to debug your code without all the pieces to the puzzle. A ROLLBACK is happening because one or more validations failed.
Any time you have a ROLLBACK you can add a ! to the create or update method being called on the object being rolled back and ActiveRecord will throw an error telling you why the ROLLBACK happened instead of failing gracefully.
Once you know why your object isn't persisting you can check the params of the controller action that form is submitting to. Perhaps you forgot to whitelist a param via strong params?
It's me again. I try to upload some yaml files with carrierwave. Everything works fine till now.
So, as you know for carrierwave the forms looks like the follow:
<%= form_for #resume, html: { multipart: true } do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name, :required => true %>
<%= f.label :attachment %><br>
<%= f.file_field :attachment, :required => true %>
<br><br>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
What i want to do now is to remove the "name" field. I don't need it. So i thought its quite easy, just remove the "name" part of the form. But then I got an error while upload:
Name can't be blank
So I tried now nearly everything... I had set the required => false same result.
I went to Github and tooked a look at their how-to... there are methods to overwrite the name, but nobody cares about upload a file without a name. May somebody can tell me how i can upload a file without this name field?
Thanks!
Edit:
My resume.rb model:
class Resume < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader # Tells rails to use this uploader for this model.
end
My AttachmentUploader:
class AttachmentUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(yml)
end
def filename
"something.jpg" if original_filename # This is the part where i'm trying around right now.
end
end
Try to remove column name on table resumes and others related,
maybe on views, controller (strong params), migration file...
Then re-run drop, migrate database
I'm trying to get file uploading to work with a nested fields_for tag in a Rails 4 app. I've followed several Railscasts, namely: 253, 381, 383, but still can't quite get it fully functioning. Also using Carrierwave & jquery file upload.
Basic app structure is as follows:
blogpost.rb
class Blogpost < ActiveRecord::Base
has_many :blogpics
end
blogpic.rb
class Blogpic < ActiveRecord::Base
belongs_to :blogpost
end
blogposts_controller.rb
def new
#blogpost = Blogpost.new
blogpic = #blogpost.blogpics.build
end
blogpost_form.html.erb
<div>
<%= form_for #blogpost do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :post_id %>
<%= f.text_field :title %>
<%= f.text_field :location %>
<%= f.text_area :content %>
<%= f.fields_for :blogpics do |builder| %>
<%= builder.file_field :image %>
<%= builder.hidden_field :blogpost_id %>
<% end %>
<p><%= f.submit %></p>
<% end %>
Uploading a single file works. But, adding ":multiple => true, :name => 'blogpic[image]'" to the file field breaks functionality and no files upload.
When I edit blogposts_controller.rb as such:
def new
#blogpost = Blogpost.new
3.times do
blogpic = #blogpost.blogpics.build
end
end
I am able to input three files individually, then upload successfully. Is there any way I can achieve this functionality while being able to drag & drop multiple files into one input?
I really appreciate any help and direction, thanks.
Your blogpost model is missing an accepts_nested_attributes association.
class Blogpost < ActiveRecord::Base
has_many :blogpics
accepts_nested_attributes_for :blogpics
end
I'm not quite sure how handling multiple files in one dialog box. I'd imagine you'd be using some javascript to detect that multiple files were selected, and creating field forms for each of them.
You can pass :multiple => true as a param on builder.file_field :image. See http://apidock.com/rails/ActionView/Helpers/FormTagHelper/file_field_tag for details
With the multiple attribute on the file input, you can drag and drop ONTO the input element
See for details http://www.html5rocks.com/en/tutorials/file/dndfiles/#toc-selecting-files
I've run into the same issue (where multiple: true breaks the nested form) and my understanding is that you have to manually transform the params before the controller receives it. If you inspect (using pry or debugger) the params hash, you need to compare between submitting Parent Model with several input files (on individual inputs) VERSUS Parent Model with multiple input files (in one input). The former creates an array of child objects (each with their own file), while the latter creates only one child object that has all the images in one array.
I wanted to try out Carrierwave_direct with my app so I decided to follow the Railscast episode. http://railscasts.com/episodes/383-uploading-to-amazon-s3
I am using Carrierwave for a variety of uploads including Images, Videos, and Songs. Right now though, I'm only testing the video to see how I like it. Right now, the video's are getting uploaded to my Amazon bucket, but the file (string) isn't getting saved to my database and not rendering on the page. Here is where I am right now...
Rails v 4.0.1
Ruby v 2.1.1
Video Uploader
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWaveDirect::Uploader
# I haven't added any resizing or anything yet
end
Video Model (video.rb)
mount_uploader :video, VideoUploader # In the database, the column is video:string
...
...
Page to upload file, before being redirected to form
def home
#uploader = Video.new.video
#uploader.success_action_redirect = new_video_url
end
Videos controller
def new
#video = Video.new(key: params[:key])
end
def create
#video = current_user.videos.create(video_params)
...
end
private
def video_params
params.require(:video).permit(:type, :title, :description, :video)
end
home.html.erb (where the video upload is BEFORE it successfully redirects you to the rest of the form)
<%= direct_upload_form_for #uploader do |f| %>
<p><%= f.file_field :video %></p>
<p><%= f.submit "Upload Video" %></p>
<% end %>
videos/_form.html.erb (the rest of the video form)
<%= form_for(#video, html: { :class => "full-form form-vertical" }) do |f| %>
<fieldset>
<%= render "shared/error_messages", object: f.object %>
<%= f.hidden_field :key %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, :class => "form-control" %>
</div>
<%= f.submit %>
</fieldset>
<% end %>
My amazon is configured properly, so I won't provide my carrierwave.rb initializer file.
So to reiterate, what's happening is on the first page, I will upload the video which will redirect me to the form. If I inspect the form, I can see that the :key has the proper value in it. But, if I put a presence validator on the model, the form won't submit because the video will be blank. And if there is no validation, the form will submit, amazon will upload it to my bucket, but (1) the video file name/string won't be stored in my db and (2) it won't render on the page, because it's empty.
Thanks for taking a look. Cheers.
#video_params needs to permit :key, in your video controller.
private
def video_params
params.require(:video).permit(:type, :title, :description, :video, :key)
end
You brought the :key all the way down, set it in #new, kept it with the hidden_field, and then lost it on the strong params.
The :key needs to get back to the VideoUploader object which is mounted under Video as :video, this is what allows your Video class to accept the :key attribute.
Video Model (video.rb)
mount_uploader :video, VideoUploader # In the database, the column is video:string
...
How do I duplicate an ActiveRecord object with a dragonfly image?
I have the following.
model:
class Event < ActiveRecord::Base
image_accessor :thumbnail
attr_accessible :thumbnail, :remove_thumbnail, :retained_thumbnail
validates :thumbnail, presence: true
end
controller:
def clone
#event = Event.find(1).dup
render :new
end
view:
<%= form_for #event do |f| %>
<%= f.label :thumbnail %>
<%= image_tag(#event.thumbnail.thumb('100x75').url) %>
<label><%= f.check_box :remove_thumbnail %> Remove?</label>
<%= f.file_field :thumbnail %>
<%= f.hidden_field :retained_thumbnail %>
<% end %>
When I render the form, the image displays, but on submit, the image gets cleared out.
One thing, I'd like to make sure they are actually different images, so if I edit the original record, it will not affect the duplicate.
Here's how I got it to work, overriding the object's dup behavior:
def dup
target = Event.new(self.attributes.reject{|k,v| ["id", "attachment_uid"].include?(k) })
target.attachment = self.attachment
target
end
Then, when you call save on the target the image will be copied to the new location.
Note that on the first line I first tried target = super, to utilize the object's default dup behavior, but that caused the files of the original object to be deleted. The above solution finally did the trick for me.