C.Yee C.Yee - 1 year ago 71
Ruby Question

nested form params blank? problems

dear fellow programmers,

I am having a little problem with my nested form within another form.. here is what i'm trying to do, this current form is to add owners to current_customer. But within this form has a nested form to input owner's telephone number into the telephones table which is separated from the owners table -- hence the nested form. Users have to enter their owners name to create a new owner, but telephone number can be added later. The said form is as follows:

<%= form_for(@owner) do |f| %>
<%= f.hidden_field :customer_id, :value => params[:id] %>

<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>

<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>

<%= f.fields_for :telephones do |t| %>
<div class="form-group">
<%= t.hidden_field :owner_id, :value => @owner.id %>

<div class="number-type">
<%= t.label :tel, "Contact number" %>
<%= t.radio_button :numbertype, "mobile", :checked => false, :class => "numbertype mobile" %>
<%= t.label :numbertype, "Mobile", :value => "mobile" %>
<%= t.radio_button :numbertype, "land", :class => "numbertype land" %>
<%= t.label :numbertype, "Land", :value => "land" %>

<%= t.text_field :number, placeholder: "telephone number", class: 'form-control some_input' %>

<%= t.text_field :ext, placeholder: "extension", id: "extension", class: 'form-control'%>
<% end %>

<%= f.submit "Add new owner", class: "btn btn-primary" %>

The telephone.rb model is as follows:

class Telephone < ActiveRecord::Base
belongs_to :customer
belongs_to :owner

validates :owner_id, presence: true, allow_blank: true
validates :customer_id, presence: true, allow_blank: true
validates :numbertype, presence: true, allow_blank: true
validates :number, presence: true, allow_blank: true,
length: { in: 7..10 }, uniqueness: { scope: [:ext] },
:numericality => {:only_integer => true}
validates :ext, presence: true, allow_blank: true


def create
@customer = Customer.find(params[:owner][:customer_id])
@owner = Owner.find_by(customer_id: params[:id])

if number_blank?
@owner = @customer.owners.build(owner_params)
@owner = @customer.owners.build(owner_with_telephone_params)

if @owner.save
@customer.update_attribute(:updated_at, Time.zone.now)
flash[:success] = "New owner added!"
redirect_to request.referrer
flash[:danger] = "no owner has been added."
redirect_to @customer


def owner_with_telephone_params
params.require(:owner).permit(:name, :email, :tel, telephones_attributes: [:numbertype, :number, :ext])

def owner_params
params.require(:owner).permit(:name, :email, :tel)

def number_blank?

the problem i am facing with my code is that even my :number field in this form is filled, the number cannot be entered into the telephone table. Is it as if rails could not detect my :number field is blank? or not. if there something that i am doing wrong? much appreciate your help!

Answer Source

When using nested forms, your nested relationship of telephone_attributes returns a hash of hashes, where each child hash can represent a different telephone record. Here's what the params look like when they are submitted to your application (assuming 1 telephone was provided):

  "owner" => {
    "telephones_attributes" => {
      "0" => {
        "number" => "555-1234"

So in this case your call to number_blank? will always be true because there is no :number value as a direct key to the :telephones_attributes hash. Instead you need to dive into the values of that hash to see if any numbers have been set. Something like this might work (untested):

def number_blank?
  params[:owner][:telephones_attributes].values.map { |telephone|

This builds a new array of all of the provided numbers from the nested fields, removes any blank elements, and checks if the array is empty. If it's empty, there are no numbers, otherwise there was at least one number provided.

However this strikes me as a lot of work for a problem that Rails might have already solved for you. Have you looked into using the :reject_if option for the accepts_nested_attributes_for call on your Owner model? You might be able to use that to reject any parameters where the number is blank so no record is created in the telephones table. This would help eliminate the conditional logic out of your controller #create action. Check out the documentation for ActiveRecord::NestedAttributes.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download