PlanItMichael
PlanItMichael

Reputation: 334

Setting User Preferences using Normalized Model in Ruby On Rails

I'm building an application (web/iOS) that allows a user to set a series of preference options. The models/tables required include:

Model Specs:

class User < ActiveRecord::Base
  has_many :user_prefs
  has_many :prefopts, through: :user_prefs

end

class Pref < ActiveRecord::Base
  has_many :prefopts
  has_many :user_prefs

  accepts_nested_attributes_for :prefopts

  validates :name, presence: true
end

class Prefopt < ActiveRecord::Base
  belongs_to :pref
  has_many :user_prefs
  has_many :users, through: :user_prefs

  accepts_nested_attributes_for :user_prefs
end

class UserPref < ActiveRecord::Base
  belongs_to :user
  belongs_to :prefopt
end

For now, I want to set the user's preferences/options on the user "show" page, so when I pull up a user's record, I see a listing of all the preferences and for each a drop-down list of the available preferences for each option.

I have updated the Users controller to query back the preferences...

  # GET /users/1
  # GET /users/1.json
  def show
    @prefs = Pref.all
  end

Also, I added to the routes file references under users:

  resources :users do
    resources :prefs do
      get 'prefopts', on: :member
    end
  end

And this works fine: on a user's "show" page I can see all the available preferences when using this syntax:

<p>
  <H2>Preferences</H2>
  <ul>
    <% @prefs.each do |pref| %>
    <li><%= pref.name %></li>
      <ul>
      </ul>

    <% end %>
  </ul>
</p>

But when I add the code to loop over each "prefopt" for each pref, I get an error.

<p>
  <H2>Preferences</H2>
  <ul>
    <% @prefs.each do |pref| %>
    <li><%= pref.name %></li>
      <ul>
      <% @pref.prefopts.each do |prefopt| %>
        <li><strong>Option: </strong><%= prefopt.name %></li>
      <% end %>
      </ul>

    <% end %>
  </ul>
</p>

Error message:

undefined method `prefopts' for nil:NilClass

Now, I've updated the pref scaffolding's show page to allow me to add and list prefopt records for each preference, and I'm using the same syntax from that view here.

If I take the error message at face value, it looks as if it thinks the "pref" is nil, but if that's the case why is the pref's name showing up correctly before I add in the prefopt?

Is there something I need to do in the view to pre-populate each pref's options? Or am I going about this all wrong? It there a best practice that I haven't found yet?

I've done extensive searching and have found some tips on working with many-to-many relationships, including:

http://www.createdbypete.com/articles/working-with-nested-forms-and-a-many-to-many-association-in-rails-4/

I can see how I can save one user record sending a long a bunch of nested attributes, if only I can get the options to display.

I've also searched for best practices in saving user preferences and none of the examples I've found allow for the flexibility to dynamically add user preferences in the future by storing them in a separate model/table. I'm tempted to simply create one table for each preference and one join table for each user and each preference, but that's not a DRY approach. I can see how to save these nested attributes, if I can only list the options available to the user for each preference.

Thanks for any thoughts on this!

Upvotes: 0

Views: 753

Answers (1)

Sander Garretsen
Sander Garretsen

Reputation: 1723

The error message you receive is because @pref is not set. Rewrite your view like this:

<% @prefs.each do |pref| %>
  <li>
    <%= pref.name %>
    <ul>
      <% pref.prefopts.each do |prefopt| %>
        <li><strong>Option: </strong><%= prefopt.name %></li>
      <% end %>
    </ul>
  </li>
<% end %>

(Note I removed the @-sign before pref on line 5)

Upvotes: 2

Related Questions