2
votes

I have user that has_one profile but not all users need a profile. I'm looking for a way to create the profile only when a checkbox is checked on the user form (either via update or create).

My models look like this -

class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile

class Profile < ActiveRecord::Base    
belongs_to :user

Ideally in my user form, I'd like to include a checkbox, when checked this would create the profile and set user_id in profile to the corresponding user ID.

I know that in my Users Controller, doing

@user.build_profile

Will create the profile on update but again, not all users need a profile created.

2

2 Answers

0
votes

Make a checkbox in your form, but without using form_for symbol 'f'.Instead use check_box_tag

check_box_tag :create_profile

now in your create /update function create profile if this box is checked

@user.build_profile  if params[:create_profile]
0
votes

I was trying something similar (using Rails 4.2.4) and arrived at this solution.

app/models/user.rb

The allow_destroy: true will allow you to destroy the profile association through a user form (more here).

class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile, allow_destroy: true

app/controllers/users_controller.rb

You'll need to build the user's associated profile instance (in the new and edit methods) for this to work correctly in the respective forms.

When editing a user it is possible that a profile association already exists. The edit method will use the associated profile if it does exists (setting the form with its values) or create a new profile instance if not.

Notice also that the user_params include profile_attributes: [:_destroy, :id] which will be the values sent by the checkbox.

def new
  @user = User.new
  @user.build_profile
end

def create
  @user = User.new(user_params)
  if @user.save
    redirect_to root_path
  else
    render :new
  end
end

def edit
  @user.profile || @user.build_profile
end

def update
  if @user.update(user_params)
    redirect_to @user
  else
    render :edit
  end
end

  private

  def user_params
    params.require(:user).permit(:name, profile_attributes: [:_destroy, :id])
  end

app/views/users/new.html.rb and app/views/users/edit.html.rb

Use the fields_for method in the form to submit data for the association (more on nested attributes, specifically one-to-one relationships, here).

Use the checkbox destroy attribute to create/destroy the associated profile. The value of the checked attribute within the curly braces sets the default state of the checkbox depending on whether or not the association exists (more under the 'More complicated relationships' header here). The '0' and '1' that follow invert the destroy method (i.e. create the association if checkbox is checked and delete it if not) (more here).

<%= form_for @user do |user| %>

  <%= user.fields_for :profile do |profile| %>
    <div class='form-item'>
      <%= profile.check_box :_destroy, { checked: profile.object.persisted? }, '0', '1' %>
      <%= profile.label :_destroy, 'Profile', class: 'checkbox' %>
    </div>
  <% end %>

  <%= user.submit 'Submit', class: 'button' %>

<% end %>

You can probably also delete the primary key id from the profile model given it is unnecessary in this scenario and this link is very useful in that regard.