1

I have two models: Personand User. A person can have a single user or no user at all, but every user have to be belong to a person.

I have set both models like so:

Person (has a has_user attribute):

has_one :user, dependent: :destroy
accepts_nested_attributes_for :user

User (has person_id attribute):

belongs_to :person
validates_presence_of :login, :password
validates_uniqueness_of :login

In the Person form I have a nested form_for that only shows up if I check a check box that also set the has_user attribute to true on the Person's form part.

My issue is that whenever I submit a person that has no user, it still tries to validate the user. How can I make it work?

UPDATE:

In my view:

  <div class="form-group">
    <%= person_form.label :has_user, :class => 'inline-checkbox' do %>
      Possui usuário
      <%= person_form.check_box :has_user, {id: "hasUser", checked: @person.has_user} %>
    <% end %>
  </div>
</div>
<div id="userPart" class="findMe"
     <% if @person.user.id.blank? %> style="display:none;"
     <% end %>>
  <h2> User: </h2>
  <div class="container">
    <%= person_form.fields_for :user do |user_form| %>
      <%= render partial: 'users/campos_user', locals: {form: user_form} %>
    <% end %>
  </div>
</div>

In my Person.js:

jQuery ->
  $(document).ready ->
    $(document).on 'turbolinks:load', #Added line
      console.log("Turbolinks ready.")
      $("#hasUser").change ->
        $("#userPart").toggle();
        return
    return
    return
  return

In my Person Controller:

 def new
    @person= Contato.new
    @person.ativo = true
    @page_title = 'Novo person'
    @person.build_user
  end

 def create
    @person = Person.new(person_params)
    respond_to do |format|
      if @person.save
        flash[:notice] = 'Contato foi criado com sucesso.'
        if @person.has_user == true
          format.html {redirect_to controller: :users, action: :new, person_id: @person.id}
        else
          format.html {redirect_to @person}
        end
        format.json {render :show, status: :created, location: @person}
      else
        flash[:warn] = "Erro ao criar contato."
        format.html {render :new}
        format.json {render json: @person.errors, status: :unprocessable_entity}
      end
    end
  end

Person's params:

def person_params
    params.require(:person).permit(:id, :company_id,
                                    :active, :name,
                                    :cargo, :celular,
                                    :email, :nascimento,
                                    :observacoes, :mensagem_instantanea,
                                    :tipo_msg_inst, :possui_usuario,
                                    user_attributes: [:login, :password, :permits, :id, :person_id, :_destroy])
end
Giovanni Di Toro
  • 797
  • 1
  • 14
  • 34

1 Answers1

1

You can reject submitting user attributes by using reject_if option

accepts_nested_attributes_for :user, :reject_if => :no_user_connected

def no_user_connected(attributes)
  attributes[:user_attributes][:login].blank?
end

This should discard the user part of the form (all user attributes). Please note that I dunno how your form or controller looks like, so you might need to build the condition differently.

You can also make the validations on user conditional. But overall the best way to avoid convoluted validation problems is to use some kind of form objects where you encapsulate the validations process. https://thoughtbot.com/blog/activemodel-form-objects

kkp
  • 436
  • 4
  • 11
  • Could I use the has_user property of the Person object? Cause I tried and it didn't work out for me. – Giovanni Di Toro Jul 21 '19 at 18:15
  • You could try. Maybe you could try and show the form and controller (including the way params get handeled) so it will be easier to help you solve this? Also what are the exact errors you are getting? ActiveRecord::ValidationError? Whats the message. – kkp Jul 21 '19 at 21:24
  • Whats the definition of person_params? I assume you are passing params for nested user there? Also are you using inverse_of on those models? Older versions do not have it, and its very helpful in those cases of nested models. – kkp Jul 22 '19 at 14:02
  • Added the params o the question. Yes, I'm using nested attributes. – Giovanni Di Toro Jul 22 '19 at 14:23
  • I think that in this situation I would refrain from simply doing a `create` in this flow, and move creation and validation to form objects and services. I don't know how experienced in RoR you are, but the controller should only be a place to call some outside services that handle the creation of objects and to redirect/render a page. When you create a validation object that initializes and validates an object, you can then call a service object that will create it (Person object) and after that will call another service to validate and then create User object. I suggest a link i posted before – kkp Jul 22 '19 at 20:12