Art
Art

Reputation: 781

Carrierwave upload works in Rails 4.x but not Rails 5

I have code that I've made into a dummy test site to validate. This code works exactly as intended when using Rails (4.2.5.1) but fails when using Rails (5.0). I do not understand where the actual issue is.

My specific error is Attachment article must exist, which tells me somehow I am not passing an article instance to this, but I just can't figure out why this works, exactly as is in a Rails 4.x instance but not in a Rails 5 beta and figure it must be something I haven't seen elsewhere. Hoping someone might know.

I have an Attachment model:

class Attachment < ApplicationRecord
  belongs_to :article
  mount_uploader :file, AttachmentUploader
end

I have an Article model:

class Article < ApplicationRecord  
  has_many :attachments, dependent: :destroy
  accepts_nested_attributes_for :attachments, reject_if: :all_blank
end

I have an Articles Controller:

class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :edit, :update, :destroy]

  # GET /articles/new
  def new
    @article = Article.new
    @article.attachments.build
  end

  def create
    @article = Article.new(article_params)

     respond_to do |format|
     if @article.save
        format.html { redirect_to @article, notice: 'Article was successfully created.' }
        format.json { render :show, status: :created, location: @article }
  else
        format.html { render :new }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
   end
  end

private
  # Use callbacks to share common setup or constraints between actions.
  def set_article
    @article = Article.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def article_params
    params.require(:article).permit(:name, :content, attachments_attributes: [:file, :file_cache])
   end
end

My forms are as you'd expect. My Article form:

<%= form_for(article) do |f| %>
  <% if article.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(article.errors.count, "error") %> prohibited this    article from being saved:</h2>

  <ul>
  <% article.errors.full_messages.each do |message| %>
    <li><%= message %></li>
  <% end %>
  </ul>
  </div>
 <% end %>

<div class="field">
  <%= f.label :name %>
  <%= f.text_field :name %>
</div>

<div class="field">
  <%= f.label :content %>
  <%= f.text_area :content %>
</div>

<div id="attachments">
  <h3>Attachments</h3>
  <%= render partial: "attachments/form", locals: { f: f, index: 0 } %>
</div>

<div class="actions">
  <%= f.submit %>
</div>

<% end %>

And my Attachments partial:

<%= f.fields_for :attachments, child_index: index do |ff| %>
  <%= ff.file_field :file, as: :file, label: "File ##{index += 1}" %>
  <%= ff.hidden_field :file_cache %>
<% end %>

Upvotes: 0

Views: 1182

Answers (2)

SacWebDeveloper
SacWebDeveloper

Reputation: 2812

As recommended in The Rails 4 Way, switch to using decent_exposure gem instead so you can keep instance variables out of your views and remove the extra find operations from the controller.

https://github.com/hashrocket/decent_exposure

class ArticlesController < ApplicationController

  expose(:article, params: :article_params)
  expose(:attachment, ancestor: :article)

  def create
    if article.save
      format.html { redirect_to article, notice: 'Article was successfully created.' }
      format.json { render :show, status: :created, location: article }
    else
      format.html { render :new }
      format.json { render json: article.errors, status: :unprocessable_entity }
    end
  end

  private

  def article_params
    params.require(:article).permit(:name, :content, attachments_attributes: [:file, :file_cache])
  end
end

In this example, the new method gets eliminated because Decent Exposure takes care of the find operation.

Upvotes: 0

Dharam Gollapudi
Dharam Gollapudi

Reputation: 6438

In the ArticlesController, for both new and create, you are assigning the Article object to @article variable. But in your form, you are using article, instead of @article. See if updating the variable will fix the issue.

Update the Article model to the following:

class Attachment < ApplicationRecord
  belongs_to :article, optional: true
  mount_uploader :file, AttachmentUploader
end

Upvotes: 1

Related Questions