我有两种模型:一种用于联系人(“ Contatos”),另一种用于用户(“ Usuarios”)。 Contatos has_one
Usuario,如下所示:
class Contato < ApplicationRecord
has_one :usuario, dependent: :destroy
accepts_nested_attributes_for :usuario,
allow_destroy: true
和
class Usuario < ApplicationRecord
has_secure_password
belongs_to :contato
validates_presence_of :login, :password
validates_uniqueness_of :login
end
我想使用一种形式来创建和编辑两个模型。我目前拥有的_form部分是这样的:
<%= form_with(model: contato, local: true) do |contato_form| %>
<%= if contato.errors.any?
showferr contato
end %>
#Here are the inputs for contato, I cut them out so it wouldn't be too long to read.
Bellow(与上述文件相同),剩下一个Contato
模型的复选框,它在模型(和数据库)中设置了一个Boolean
,告知联系人是否有用户并非如此,此外,我还根据复选框的值使用了JavaScript (Coffee)
至toggle
来构成整个用户(Usuario)
的一部分。
<div class="form-group">
<%= contato_form.label :possui_usuario, :class => 'inline-checkbox' do %>
Possui usuário
<%= contato_form.check_box :possui_usuario, {id: "hasUser", checked: @contato.possui_usuario} %>
<% end %>
</div>
</div>
<div id="userPart" class="findMe" <% unless @contato.possui_usuario %> style="display:none;" <% end %> >
<h2> Usuário: </h2>
<div class="container">
<%= contato_form.fields_for :usuario, @contato.usuario do |usuario_form| %>
<%= render partial: 'usuarios/campos_usuario', locals: {form: usuario_form, object: @contato} %>
<% end %>
</div>
</div>
<br/>
<div class="container-fluid text-right">
<%= contato_form.submit 'Confirmar', :class => 'btn-lg btn-success' %>
</div>
<% end %>
Usuario模型的部分形式可以正常显示,但我要做的是仅在选中复选框的情况下创建和/或验证用户部分(如果我说联系人确实有用户)。
这是我上次尝试的次数(尝试次数很多):
在Contato
模式下:
attr_accessor(:has_user)
@has_user = 0
before_validation do |record|
@has_user = record.possui_usuario
end
def self.user?
@has_user == 1
end
validates_presence_of :nome
validates_length_of :nome, in: 1..45
validates_presence_of :email
validates_format_of :email, with: email_regex
validates_associated :usuario, if: user?
Contato
的控制器:
class ContatosController < ApplicationController
before_action :set_contato, only: [:show, :edit, :update, :destroy]
# GET /contatos
# GET /contatos.json
def index
@contatos = Contato.all
@page_title = 'Contatos'
end
# GET /contatos/1
# GET /contatos/1.json
def show
@page_title = 'Ver contato: ' + @contato.nome
end
# GET /contatos/new
def new
@contato = Contato.new
@contato.build_usuario
@contato.ativo = true
@page_title = 'Novo contato'
end
# GET /contatos/1/edit
def edit
@page_title = 'Editar contato: ' + @contato.nome
unless @contato.possui_usuario
@contato.build_usuario
end
end
# POST /contatos
# POST /contatos.json
def create
@contato = Contato.new(contato_params)
respond_to do |format|
if @contato.save
flash[:notice] = 'Contato foi criado com sucesso.'
format.html {redirect_to @contato}
format.json {render :show, status: :created, location: @contato}
else
flash[:warn] = "Erro ao criar contato."
format.html {render :new}
format.json {render json: @contato.errors, status: :unprocessable_entity}
end
end
end
# PATCH/PUT /contatos/1
# PATCH/PUT /contatos/1.json
def update
respond_to do |format|
if @contato.update(contato_params)
format.html {redirect_to @contato, notice: 'Contato foi atualizado com sucesso.'}
format.json {render :show, status: :ok, location: @contato}
else
format.html {render :edit}
format.json {render json: @contato.errors, status: :unprocessable_entity}
end
end
end
# DELETE /contatos/1
# DELETE /contatos/1.json
def destroy
@contato.destroy
respond_to do |format|
format.html {redirect_to contatos_url, notice: 'Contato deletado com sucesso.'}
format.json {head :no_content}
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_contato
@contato = Contato.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def contato_params
params.require(:contato).permit(:id, :empresa_id,
:ativo, :nome,
:cargo, :celular,
:email, :nascimento,
:observacoes, :mensagem_instantanea,
:tipo_msg_inst, :possui_usuario,
usuario_attributes: [:login, :password, :permissoes, :id, :contato_id, :_destroy])
end
end
很抱歉,问题很长,代码块很大。
答案 0 :(得分:1)
我看到当前显示的数据有两个漏洞...
首先,在调用create
的控制器操作中,应进行测试以查看是否正在调用模型/ activerecord。
类似...
def create
if @contato && @contato.usuarios # might be able to just do last half
respond_to do |format|
if @contato = @contato.create!(contato_params) # note the bang or '!'
format.html { redirect_to @contato, notice: 'contato was successfully created.' }
else
format.html { render :new }
end
end
end
end
没有看到您的控制器-我猜您没有通过Rails strong_param功能正确嵌套控制器。注意这里-这两个不会运行,我不太确定需要什么信息,但是我想让您确定是否要嵌套模型并使用单个控制器-您已经离开了,需要嵌套模型strong_params(Google搜索嵌套的rails strong_params提供了成千上万的帮助/点击)。
params.require(:contato).permit(:login, :password, usuario: [id, ...] )
如果不是,还请告诉我们创建/读取/更新/销毁的所有功能是否正常工作,而您只是想在某些情况下限制它的创建?
基于控制器的更新-只需在#create
操作开始时将您要创建的检查从模型中移到控制器中,然后再将其移到控制器中即可...
def create
# Note - here you will have to inspect contato_params to find syntax
if contato_params[:usuario_attributes][:contato_id]
... rest of action wrapped in here ...
end
end
...再次...您将需要确定确切的语法-但就像您进行编辑一样-在此位置您可以控制创建-不在模型中。
更具体地说,我看到以下形式的@contato.possui_usuario
...这可能是您要在控制器中检查的变量,但也许我的建议更重要-我不能确定地告诉您-我也不确定您是否需要在模型中说出has_user
技巧,并且可能会想在私有方法部分中尝试制作控制器版本...
class ContatosController
private
def has_user?
... whatever ...
end
注释中的说明:
如果我将控件从用户表单部分移至控制器( 很有道理)我该如何取消 如果用户决定将模型的validates_associated部分 该联系人没有用户吗?
您无需移动表单控件(在表单中定义为变量),而是将处理表单控件的模型方法移至控制器-然后可以将其全部包装在事务中以回滚其他任何更改,或者如果您使用#build来建立activerecord,它将为您完成。