Reputation: 781
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
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
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