Rails-验证复杂的嵌套形式 [英] Rails - Validating complex nested form
问题描述
我有一个带有四个输入字段的表单,用户可以在其中创建一个item
.在表单中,四个输入字段之一是图片,用于在提交表单时同时创建user_item
.我遇到了几个问题.
I have a form with four input fields where a user creates an item
. In the form one of the four input fields is for picture which is used to create a user_item
at the same time on form submission. I am running into several problems.
-
当
item
上的验证失败时,我具有控制器render :new
,但是发生这种情况时,图片输入字段不可见.
When validation fails on the
item
I have the controllerrender :new
but when this happens the picture input field is not visible.
验证图片是否有效.
我需要一种在创建user_item
时将user_id
属性设置为current_user
的方法.
I need a way to set the user_id
attribute to current_user
on the user_item
when it is created.
item.rb
validates :name, presence: true, uniqueness: true
validates :description, presence: true
has_many :tags
has_many :user_items
has_many :users, -> { uniq }, through: :user_items
belongs_to :user
accepts_nested_attributes_for :user_items
validates_associated :user_items
user_item.rb
belongs_to :user
belongs_to :item
mount_uploader :picture, PictureUploader
validates_presence_of :picture
validate :picture_size
items_controller.rb
def new
@item = Item.new
@item.user_items.build
end
def create
@item = item.new item_params
if @item.save
redirect_to items_path, notice: "Thank you for your item request!"
else
render :new
end
end
private
def item_params
params.require(:item).permit(:name, :description, :tag_list, user_items_attributes: [:picture]).merge(created_by: current_user.id)
end
new.html.erb
<%= simple_form_for @item, html: { class: "create-item-form" } do |item_builder| %>
<div class="well">
<%= item_builder.input :name, required: false, error: false, label: "Item name" %>
<%= item_builder.input :description, as: :text, required: false, error: false, label: "Description of item" %>
<%= item_builder.input :tag_list, required: false, label: "Tags (these will help users find your item)" %>
<%= item_builder.simple_fields_for :user_items do |user_item_builder| %>
<%= user_item_builder.input :picture, as: :file, required: false, label: "Picture of you with this item" %>
<% end %>
</div>
<div class="clearfix">
<%= item_builder.submit 'Submit new item request', class: "btn btn-primary pull-right inherit-width" %>
</div>
<% end %>
推荐答案
我需要一种设置
user_id
将user_id
添加到user_item
的最简单方法是包含 hidden_field
在您的fields_for
中.不是最安全,但应该可以工作:
The simplest way to add the user_id
to the user_item
is to include a hidden_field
in your fields_for
. Not the most secure, but should work:
#app/views/items/new.html.erb
...
<%= item_builder.simple_fields_for :user_items do |user_item_builder| %>
<%= user_item_builder.input :picture, as: :file, required: false, label: "Picture of you with this item" %>
<%= user_item_builder.input :user_id, as: :hidden, input_html: { value: current_user.id } %>
<% end %>
#app/controllers/items_controller.rb
...
def item_params
params.require(:item).permit(:name, :description, :tag_list, user_items_attributes: [:picture, :user_id]).merge(created_by: current_user.id)
end
图片输入字段不可见
the picture input field is not visible
根据以下答案: Nested Input Disappears When Form Reloads
,您需要重建picture
对象:
According to this answer: Nested Input Disappears When Form Reloads
, you need to rebuild your picture
objects:
def create
if @item.save
...
else
@item.user_items.build
render :new
end
end
file_field
输入特别有趣.由于您的操作系统无法保证您的文件将与之前的文件完全相同,因此不会填充file_field
.
file_field
inputs are particularly interesting. Because your OS cannot guarantee your files will be exactly the same as they were, so the file_field
is not populated.
存在图片的验证不起作用.
Validation on presence of picture is not working.
您应该使用inverse_of
来确保两个对象可以互相通话:
You should use inverse_of
to make sure the two objects can talk to each other:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :user_items, inverse_of: :user
end
#app/models/user_item.rb
class UserItem < ActiveRecord::Base
belongs_to :user, inverse_of: :user_items
validates :picture, presence: true
end
更新
如果您想通过后端传递user_id
,而不需要隐藏字段,则可以执行以下操作:
If you wanted to pass the user_id
through the backend, not having a hidden field, you'd be able to do something like this:
#app/controllers/items_controller.rb
class ItemsController < ApplicationController
def new
@user = current_user
@user.user_items.build.build_item
end
def create
@user = current_user.update user_params
end
private
def user_params
params.require(:user).permit(user_items_attributes: [:picture, item_attributes: [:name, :description, :tag_list])
end
end
这必须伴随对items#new
视图的以下更改:
This would have to be accompanied with the following change to your items#new
view:
<%= simple_form_for @user, url: items_path, html: { class: "create-item-form" } do |f| %>
<%= f.fields_for :user_items do |user_item_builder|
<%= user_item_builder.input :picture, as: :file, required: false, label: "Picture of you with this item" %>
<%= user_item_builder.fields_for :item do |item_builder| %>
<%= item_builder.input :name, required: false, error: false, label: "Item name" %>
<%= item_builder.input :description, as: :text, required: false, error: false, label: "Description of item" %>
<%= item_builder.input :tag_list, required: false, label: "Tags (these will help users find your item)" %>
<% end %>
<% end %>
<%= f.submit 'Submit new item request', class: "btn btn-primary pull-right inherit-width" %>
<% end %>
您还需要通过相应的模型传递属性:
You'll also need to pass the attributes through the respective models:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :user_items
has_many :items, through: :user_items
accepts_nested_attributes_for :user_items
end
#app/models/user_item.rb
class UserItem < ActiveRecord::Base
belongs_to :user
belongs_to :item
accepts_nested_attributes_for :item
end
这篇关于Rails-验证复杂的嵌套形式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!