2

I created a Preference model to manage email settings. Right now, the nested form is not showing up on the actual page. I tried a series of different tactics, but can't figure it out.

I made sure I had preferences locally set up, changed the fields_for to (@user.preference) which didn't work, etc.

I'm using Rails 4.2.2, Ruby version 2.2.1.

schema

  create_table "preferences", force: :cascade do |t|
    t.datetime "created_at",                    null: false
    t.datetime "updated_at",                    null: false
    t.integer  "user_id",                       null: false
    t.boolean  "new_match",      default: true, null: false
    t.boolean  "accepted_match", default: true, null: false
    t.boolean  "match_reminder", default: true, null: false
    t.boolean  "new_message",    default: true, null: false
  end

user model

  has_one :preference, dependent: :destroy
  accepts_nested_attributes_for :preference

preference model

class Preference < ActiveRecord::Base
  belongs_to :user
end

actual form that has contains the partials to the nested form:

<%= form_for(@user, id: "editing-info") do |f| %>
  <ul class="tabs">
    <li class="tab-link current" data-tab="tab-account">
      <%= t("edit_user.tabs.account") %>
    </li>
    <li class="tab-link" data-tab="tab-interests">
      <%= t("edit_user.tabs.interests") %>
    </li>
    <li class="tab-link" data-tab="tab-settings">
      <%= t("edit_user.tabs.settings") %>
    </li>
  </ul>

  <div class="tab-content current" id="tab-account">
    <%= render "users/tabs/account", f: f %>
  </div>  

  <div class="tab-content" id="tab-interests">
    <%= render "users/tabs/interests", f: f %>
  </div>

  <div class="tab-content" id="tab-settings">
    <%= render "users/tabs/settings", f: f %>
  </div>

  <div id="button-container">
    <%= link_to 'Cancel',
      user_path(current_user),
      data: { disable_with: "Loading..." },
      class: "cancel-desktop" %>

    <%= f.submit "Save",
      data: { disable_with: "Loading..." },
      class: "save main-save-button-edit" %>
  </div>
<% end %>

partial that includes nested form

<div id="settings">
  <h4 class="notifications-label">Notifications</h4>
  <div class="notifications setting-category info-holder">
    <div class="mobile setting-holder">
      <%= f.label :mobile, "Mobile", class: "setting-label" %>
      <%= f.text_area :mobile, placeholder: "Add mobile number", class: "setting-input" %>
    </div>
    <div class="email-holder setting-holder main-email-edit">
      <%= f.label :email, "Email", class: "setting-label" %>
      <%= f.text_area :email, placeholder: "Add email address", class: "setting-input" %>
    </div>
    <p class="setting-descrip">This email is where Glassbreakers notifications will be sent. Please continue to use your email associated with your LinkedIn account to sign in.</p>
  </div>
  <h4 class="email-label">Emails</h4>
  <%= f.fields_for :preference do |user_preference| %>
    <div class="email-notifications-holder">
      <div class="email-holder">
        <%= user_preference.label :new_match, "Getting a new match each week" %>
        <%= user_preference.check_box :new_match, class: "checkbox new_match_email" %>
      </div>
      <div class="email-holder">
        <%= user_preference.label :match_reminder, "New matches Thursday reminder", class: "match_reminder_email" %>
        <%= user_preference.check_box :match_reminder, class: "checkbox thursday_reminder_email"   %>
      </div>
      <div class="email-holder">
        <%= user_preference.label :accepted_match, "A Glassbreakers accepted a match", class: "accepted_match_email" %>
        <%= user_preference.check_box :accepted_match, class: "checkbox accept_match_email"   %>
      </div>
      <div class="email-holder">
        <%= user_preference.label :new_message, "Received a new message" %>
        <%= user_preference.check_box :new_message, class: "checkbox new_message_email"  %>
      </div>
    </div>
  <% end %>
  <h4 class="connect-label">Connections</h4>
  <div class="connections info-holder">
    <p class="inform">You'll receive new matches every Tuesday. Make sure to respond to your matches before then.</p>
    <div class="pausing">
      <label><%= t("edit_user.settings.pausing_header") %></label>
      <%= react_component(
        "MatchingPausedSetting",
        {
          matchingPaused: current_user.matching_paused?,
          pauseMatchingURL: user_matching_pauses_path(current_user)
        }
      ) %>
    </div>
    <p class="setting-descrip pause-descrip">Pausing connections means you will not receive new potential connections each week. You will be able to send and receive new messages.</p>
  </div>
  <h4 class="contact-label">Contact</h4>
  <div id="contact-info" class="info-holder">
    <p class="inform">Have a question?  We love hearing from you. Contact Courtney, our communication manager, at <a href="mailto:info@glassbreakers.co" target="_top">info@glassbreakers.co</a>.</p>
  </div>
</div>

user controller pertaining to the user_params

  def user_params
    filtered_params = params.require(:user).permit(
      :email,
      :mobile,
      :bio_because,
      :bio_meet,
      :description,
      :github_link,
      :linkedin_link,
      :title,
      :twitter_link,
      preference_attributes: [
        :id,
        :new_match,
        :accepted_match,
        :match_reminder,
        :new_message,
      ],
      user_onboard_skills_attributes: [
        :skill_id,
        :industry_id,
        :years_experience,
        :id,
        :_destroy,
      ],
      interest_ids: [],
    )

    filtered_params[:user_onboard_skills_attributes] =
      filter_user_onboard_skills_attributes(
        filtered_params[:user_onboard_skills_attributes]
      )

    filtered_params
  end
LMo
  • 1,429
  • 2
  • 15
  • 32

2 Answers2

1

If your nested form is actually within the user form itself, adjusting your fields_for declaration like so should do the trick:

<%= f.fields_for @user.preference do |preference_fields| %>

Also note that I renamed the block variable to preference_fields from f, as it looks like you are already using f for your parent form.

The documentation has great explanation of this method, which should answer any additional questions:

fields_for documentation

Edit for posterity:

The fields weren't correctly displaying because your User model did not have an associated Preference model, this can be fixed by manually associating a preference model to the User, or by utilizing a strategy similar to the one found in this question: Rails: Create association if none is found to avoid nil errors. Pre-cautions are taken at the model level to ensure the association is created whenever a new User is created.

Community
  • 1
  • 1
BK22
  • 85
  • 3
  • Hi @BK22 - when i updated the above recommendations, I received the error "undefined method `model_name' for nil:NilClass" – LMo Jul 09 '15 at 19:02
  • It would be helpful if you posted your entire form view and controller method. From that error it sounds like the user doesn't have a preference associated with it. – BK22 Jul 09 '15 at 20:17
  • Added the full form that has a partial of the settings form, which includes the nested partial. – LMo Jul 09 '15 at 20:38
  • Make sure that the user being modified has an associated Preference model. – BK22 Jul 09 '15 at 20:54
  • You were right. I created the default preferences for an incorrect user on the back end. However, now I'm getting the problem "found unpermitted parameter: preference" with the same set up as above. – LMo Jul 09 '15 at 21:18
0

You cannot get both fields for user and preferences using 'f'. you need to get fields_for preferences using

 <%= f.fields_for :preference do |user_preference| %>

and for preferences field you will use user_preference

Athar
  • 3,258
  • 1
  • 11
  • 16