Rails-仅在满足条件时发送关联表单

时间:2019-01-30 15:14:02

标签: ruby-on-rails forms validation ruby-on-rails-5

我有两种模型:一种用于联系人(“ 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

很抱歉,问题很长,代码块很大。

1 个答案:

答案 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,它将为您完成。