I'm working on a small project in Rails loosely following the Rails Tutorial. I have Carrierwave, Fog, and AWS working wonderfully on production for uploading a single image. I wanted to add a gallery of images, so I figured I would follow SSR's answer in the link: Rails 4 multiple image or file upload using carrierwave
Everything seems to work well for my model, and the tests even pass, but when I go to create or edit a listing, the uploader doesn't seem to work. It will hang for minutes without resolving (even on small file sizes), and the console doesn't read that an action was posted on submitting (just reads 200 for the last GET for the form itself). Other than naming conventions (I use Listing as the Post model and listing_gallery instead of post_attachment), the steps were identical. Did Rails 5 change anything about Carrierwave?
listing.rb
class Listing < ApplicationRecord
VALID_PHONE_REGEX = /(\(*(\d{3})\)|(\d{3}-)|(\d{3}))\s*(\d{3})-*(\d{4})/
VALID_ZIP_REGEX = /\d{5}((-)?\d{4})?/
# One use has many listings
belongs_to :user
# Listing_gallery
has_many :listing_galleries
accepts_nested_attributes_for :listing_galleries
# Descending order from newest to oldest as default
default_scope -> { order(created_at: :desc) }
# Carrier Wave mount uploader for images
mount_uploader :picture, PictureUploader
mount_uploader :image, PictureUploader
# Validation of parameters before accepting listing
validates :user_id, presence: true
validates :description, presence: true
validates :street_address, presence: true
validates :city, presence: true, length: { maximum: 30 }
validates :zip_code, presence: true, length: {minimum: 5, maximum: 10}, format: { with: VALID_ZIP_REGEX }
validates :primary_contact, presence: true, length: {minimum: 10, maximum: 15}, format: { with: VALID_PHONE_REGEX }
end
listings_controller.rb
class ListingsController < ApplicationController
before_action :logged_in_user, only: [:new, :create, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
def new
@listing = Listing.new
@listing_gallery = @listing.listing_galleries.build
end
def create
if current_user.admin?
@listing = current_user.listings.build(listing_params)
@listing.listing_status = "active"
respond_to do |format|
if@listing.save!
params[:listing_galleries]['image'].each do |image|
@listing_gallery = @listing.listing_galleries.create!(:image => image)
end
flash[:success] = "New Listing created!"
redirect_to root_url
else
render 'new'
end
end
else
flash[:failure] = "You must be an admin to create a listing."
redirect_to root_url
end
end
def show
@listing = Listing.find(params[:id])
@listing_galleries = @listing.listing_galleries.all
end
def edit
if current_user.admin?
@listing = Listing.find(params[:id])
render 'edit'
end
end
def update
if current_user.admin?
@listing = Listing.find(params[:id])
respond_to do |format|
if @listing.update_attributes(listing_params)
if params[:listing_galleries] != []
params[:listing_galleries]['image'].each do |image|
@listing_gallery = @listing.listing_galleries.create!(:image => image)
end
end
flash[:success] = "Listing Updated!"
redirect_to @listing
else
render 'edit'
end
end
end
end
def destroy
if current_user.admin?
@listing.listing_status = "deleted"
if @listing.save!
flash[:success] = "Listing DELETED"
redirect_to request.referrer || root_url
else
flash[:failure] = "Could not remove listing"
redirect_to request.referrer || root_url
end
end
end
private
# Check for necessary paramters
def listing_params
params.require(:listing).permit(:description, :street_address, :city, :state,
:zip_code, :primary_contact, :secondary_contact,
:listing_status, :asking_price, :renobb, :picture,
{ image: [] },
listing_galleries_attributes: [:id, :listing_id, :image, :_destroy])
end
# Ensure only the creator of the listing is destroying it
def correct_user
@listing = current_user.listings.find_by(id: params[:id])
if current_user.admin?
return true
end
redirect_to root_url if @listing.nil?
end
end
listings/new.html.erb
<% provide(:title, 'Create Listing') %>
<div id="content">
<div id="sectionbanner">
<p class="goldtext">
Create a New Listing
</p>
</div>
<!-- Article -->
<div id="article">
<div class="form">
<%= form_for(@listing, html: { multipart: true}) do |form| %>
<%= render 'shared/error_messages_listings' %>
<%= form.label :street_address %>
<br>
<%= form.text_field :street_address, class: 'form-control' %>
<br>
<%= form.label :city %>
<br>
<%= form.text_field :city, class: 'form-control' %>
<br>
<%= form.label :state %>
<br>
<%= form.text_field :state, class: 'form-control' %>
<br>
<%= form.label :zip_code %>
<br>
<%= form.text_field :zip_code, class: 'form-control' %>
<br>
<%= form.label :primary_contact %>
<br>
<%= form.text_field :primary_contact, class: 'form-control' %>
<br>
<%= form.label :secondary_contact %>
<br>
<%= form.text_field :secondary_contact, class: 'form-control' %>
<br>
<%= form.label :asking_price %>
<br>
<%= form.number_field :asking_price, class: 'form-control' %>
<br>
<%= form.label :description %>
<br>
<%= form.text_area :description, placeholder: "Details of the lot, rules, etc..." %>
<br>
<%= form.label :renobb %>
<br>
<%= form.check_box :renobb %>
<br>
<span class="picture">
<%= form.file_field :picture, accept: 'image/jpeg, image/gif, image/png' %>
</span>
<br>
<%= form.label :image %>
<br>
<%= form.file_field :image, :multiple => true, name: "listing_galleries[image][]" %>
<br>
<%= form.submit "Create Listing", class: "button" %>
<% end %>
</div>
</div>
</div>
listing_gallery.rb
class ListingGallery < ApplicationRecord
belongs_to :listing
mount_uploader :image, PictureUploader
end
listing_galleries_controller.rb
class ListingGalleriesController < ApplicationController
before_action :set_listing_gallery, only: [:show, :edit, :update, :destroy]
# GET /listing_galleries
# GET /listing_galleries.json
def index
@listing_galleries = ListingGallery.all
end
# GET /listing_galleries/1
# GET /listing_galleries/1.json
def show
end
# GET /listing_galleries/new
def new
@listing_gallery = ListingGallery.new
end
# GET /listing_galleries/1/edit
def edit
end
# POST /listing_galleries
# POST /listing_galleries.json
def create
@listing_gallery = ListingGallery.new(listing_gallery_params)
respond_to do |format|
if current_user.admin?
if @listing_gallery.save
format.html { redirect_to @listing_gallery, notice: 'Listing gallery was successfully created.' }
format.json { render :show, status: :created, location: @listing_gallery }
else
format.html { render :new }
format.json { render json: @listing_gallery.errors, status: :unprocessable_entity }
end
end
end
end
# PATCH/PUT /listing_galleries/1
# PATCH/PUT /listing_galleries/1.json
def update
respond_to do |format|
if current_user.admin?
if @listing_gallery.update(listing_gallery_params)
format.html { redirect_to @listing_gallery, notice: 'Listing gallery was successfully updated.' }
format.json { render :show, status: :ok, location: @listing_gallery }
else
format.html { render :edit }
format.json { render json: @listing_gallery.errors, status: :unprocessable_entity }
end
end
end
end
# DELETE /listing_galleries/1
# DELETE /listing_galleries/1.json
def destroy
if current_user.admin?
@listing_gallery.destroy
respond_to do |format|
format.html { redirect_to listing_galleries_url, notice: 'Listing gallery was successfully destroyed.' }
format.json { head :no_content }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing_gallery
@listing_gallery = ListingGallery.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_gallery_params
params.require(:listing_gallery).permit(:listing_id, :image, { image: [] }, :_destroy)
end
end
EDIT More files from the controllers and views. (Alignment may be funky on SO, but it's alright in project.)