轨道 - 生成是否会影响创建的子记录数?



一篇文章has_many图片。创建新文章时,用户最多可以添加 2 张图片。

在我的控制器中,我只对图像运行"构建"两次,但是当我提交具有 3 个图像字段的表单时,它成功了。是否需要运行"构建"?在这种情况下似乎毫无意义,有没有另一种方法可以更好地确保只接受 2 张图像?

articles_controller.rb

def new
@article = Article.new
2.times { @article.images.build }
end

请注意此处的"2.times"。

def create
@article = Article.new(place_params)
@article.user = current_user
respond_to do |format|
if @review.save
params[:images][:image_file].each do |image_params|
@image = @article.images.create(image_file: image_params, user: current_user)
end
end
end
end

_form.html.erb

<%= form_with(model: article, url: create_article_path(@article), local: true) do |form| %>
<div class="field">
<%= form.label :title %> 
<%= form.text_area :title %>
</div>
<%= form.fields_for :images, @image do |image| %>
<div class="field">
<%= image.label :image_file_1, "Image 1" %>
<%= photo.file_field :image_file, name: "images[image_file][]", id: :article_images_image_file_1 %>
</div>
<div class="field">
<%= image.label :image_file_2, "Image 2" %>
<%= photo.file_field :image_file, name: "images[image_file][]", id: :article_images_image_file_2 %>
</div>
<div class="field">
<%= image.label :image_file_3, "Image 3" %>
<%= photo.file_field :image_file, name: "images[image_file][]", id: :article_images_image_file_3 %>
</div>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>

成功(但为什么?

简而言之 -- 您的构建语句正在准备具有 2 个子对象的视图。 但是您是手动创建它们的,因此您将构建语句呈现为无用。 您不必这样做,您可以在模型中声明嵌套属性,然后在控制器中加入白名单,然后在视图中自动添加它们。 (请参阅下面的代码示例(

构建本身确实会更改实例化的对象数,但您正在覆盖它。

您还手动保存图像,而不必这样做。 有一点轨道魔法可以为你拯救所有的孩子,如果你正确地建造了他们。

代码视图

1 模型

app/models/article.rb

class Article < ApplicationRecord
has_many :images
validates :images, length: {maximum: 2}
accepts_nested_attributes_for :images
end

这里有 2 点注意事项。 首先,在您的验证中,只允许 2 个对象,如果您尝试保存第三个对象,它将失败。 其次,接受模型中的属性允许您在控制器中创建安全参数,从而减轻手动创建的需要。(当然,除非你真的想(

2 景观

<%= form_with(model: article, url: article_path(@article), local: true) do |form| %>
<div class="field">
<%= form.label :title %> 
<%= form.text_area :title %>
</div>
<%= form.fields_for :images do |image_form| %>
<div class="field">
<%= image_form.label "image_file_#{image_form.index + 1}" %>
<%= image_form.file_field :image_file %>
<%= image_form.hidden_field :user_id, value: current_user.id %>
</div>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>

这里的变化是 a(我将用户直接添加到表单 b.(因为您正在接受模型中的属性,并且我们会在控制器中将属性列入白名单,所以您无需将对象传递给field_for -:images就可以了。 而且因为你会说在控制器中构建它两次,所以表单中将有 2 个图像对象。 此外,由于您需要图像 1 和图像 2 的标签,因此通过调用object.indexfields_for 自动访问对象的索引(就像使用任何数组一样(。

3 控制器 - 新动作

app/models/article.rb

你的动作效果很好,保持原样。

def new
@article = Article.new
2.times { @article.images.build }
end

4 控制器 - 强参数

def article_params
params.require(:article).permit(:title, :body, images_attributes: [:id, :article_id,:user_id, :image_file])
end

将参数完全列入白名单将节省时间,并且比在每个控制器中允许它们更容易阅读,尽管如果需要,您可以这样做,例如,如果在某些操作中允许参数,但在其他操作中不允许。

5 控制器 - 创建操作

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

如果不是与基架中的默认创建操作相同,这可能看起来很相似,这就是您所需要的。 除非可以创建父图像对象,否则不会创建子图像对象,因此您不必担心将它们添加到 if save 中。

最新更新