1

I have a user model and a town model. A user belongs_to a town:

# models/user.rb
class User < ApplicationRecord
  belongs_to :town
  accepts_nested_attributes_for :town
  validates :last_name, presence: true
end


# models/town.rb
class Town < ApplicationRecord
  has_many :users
  validates :name, presence: true
  validates :name, uniqueness: true
end

You go to create a new user record: there is a text_box in order to put in the associated town's name. When submitted, the rails application should do the following:

  • use find_or_create_by. go and check if there already exists a town record with the name attribute passed in.
    • If a town record DOES exist with that given name attribute, just associate that existing town record to this new user record
    • If a town record DOES NOT exist with that given name attribute, then create a new town record with that name attribute, and associate that one to this user record
  • If any validations fail, do not create a user record or a town record and re-render the form.

I am having real trouble with this. This question suggests putting autosave on the belongs_to :town statement, as well as defining a method called autosave_associated_records_for_town. However: I just could not get that to work.

Appreciate it!

Community
  • 1
  • 1
Neil
  • 4,578
  • 14
  • 70
  • 155

1 Answers1

4

Please, try that solution. It works for me.

User

# user.rb

class User < ActiveRecord::Base
  belongs_to :town

  accepts_nested_attributes_for :town
  validates :last_name, presence: true
end

Town

# town.rb

class Town < ActiveRecord::Base
  has_many :users
  validates :name, presence: true
end

Controller

# users_controller.rb

respond_to :html    

def create

  # ...
  @user = User.new(user_params)
  @user.town = Town.find_or_initialize_by(user_params[:town_attributes])
  if @user.save
    respond_with(@user)
  else
    render 'new'
  end
end

# ...

def user_params
  params.require(:user).permit(:last_name, :email, :town_id, town_attributes: [:name])
end

View

# users/_form.html.erb

<%= form_for(@user) do |f| %>

  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :email %><br>
    <%= f.text_field :email %>
  </div>


  <div class="field">
    <%= f.label :last_name %><br>
    <%= f.text_field :last_name %>
  </div>

  <%= f.fields_for :town, @town do |bldr| %>
    <div class="field">
      <%= bldr.label :name, 'Town name' %><br>
      <%= bldr.text_field :name %>
    </div>
  <% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Validations

UPDATE

Please consider to add validates_associated to user's validations as well. Here is the related documentaion

class User < ActiveRecord::Base
  belongs_to :town

  accepts_nested_attributes_for :town
  validates :last_name, presence: true
  validates :town, presence: true
  validates_associated :town
end

enter image description here

Generaly speaking, you could remove validates :town, presence: true in that case. Validations will work without it.

Neil
  • 4,578
  • 14
  • 70
  • 155
retgoat
  • 2,414
  • 1
  • 16
  • 21