Rails - отправлять связанную форму, только если условие выполнено - PullRequest
0 голосов
/ 30 января 2019

У меня есть две модели: одна для контактов ("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.

Ниже (тот же файл, что и выше) есть флажок для модели 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 голосов
/ 30 января 2019

Я вижу две дыры в данных, представленных в настоящее время ...

Во-первых, ваше действие контроллера, где вызывается 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 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, она сделает это за вас.

...