0

I had problems with forms using polymorphic association for an user sign-up. I want to show fields from multiple models of polymorphic association, but I can't.

Model Classes:

class User < ActiveRecord::Base
  devise ...

  belongs_to :userable, :polymorphic => true
end

class Advisor < ActiveRecord::Base
  has_one :user, :as => :userable
  attr_accessible :extra
  accepts_nested_attributes_for :user # Idon't know if it is ok
end
class AnotherKingOfUser < ActiveRecord::Base
  #the same..
end

I want to make a controller for each specific User type, so:

class AdvisorsController < ApplicationController
  # GET /advisors/new
  # GET /advisors/new.json
  def new
    # Here is where I'm not sure about what I did. I tried all variants buy any works for me.
    @advisor = Advisor.new
    @advisor.build_user

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @advisor }
    end
  end
end

And my view:

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

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

 <% #f.fields_for :user do |ff| %>
 <% f.fields_for :user_attributes, @advisor.user||User.new do |ff| %>

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

    <div class="field">
      <%= ff.label :password %><br />
      <%= ff.text_field :password %>
    </div>
  <% end %>

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


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

So in my browser only appears "bio" field, but don't appear extended fields from User model (Devise).

Martin B.
  • 760
  • 2
  • 8
  • 21

2 Answers2

1

When you're working with association in a form like that (usually with a accepts_nested_attributes_for like in your case), you need to create objects in order for them to be displayed on the form.

That means that here, when rails builds your form, it looks for the content of @advisor.user which is empty because I guess that in your controller you did something like

@advisor = Advisor.new

So if you want the fields for the user to appear, you need to build a user

@advisor = Advisor.new
@advisor.build_user # this will create a instance of User, but will not persist it

With that rails will find the user when building the form, and then displays the field you want.

I hope that answers your question.

pjam
  • 6,356
  • 5
  • 30
  • 40
  • Thanks @pjam, that has sense, but it throw the following error: undefined method `build' for nil:NilClass – Martin B. Mar 17 '13 at 01:52
  • I assumed that `@advisor` was an instance of either `UserA` or `UserB`, could you add to the original post the entire controller code that takes care of `@advisor` instanciation ? – pjam Mar 17 '13 at 04:05
  • Yes, sorry for confusion. I edited post using real class names, now I implemented build_user method and don't throw any error but still showing without User fields on form view. – Martin B. Mar 17 '13 at 07:12
  • My bad, I was not using the correct method see here : http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to – pjam Mar 17 '13 at 14:33
1
class Advisor < ActiveRecord::Base
  has_one :user, :as => :userable
  attr_accessible :extra, :user_attributes
  accepts_nested_attributes_for :user # its ok
end

class AdvisorsController < ApplicationController

  def new
    @advisor = Advisor.new
    # @advisor.build_user   # unnecessary

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @advisor }
    end
  end
end

# view
<%= form_for(@advisor) do |f| %>
  <%= f.fields_for :user_attributes, @advisor.user||User.new do |ff| %>
    <div class="field">
      <%= ff.label :email %><br />
      <%= ff.text_field :email %>
    </div>
    <div class="field">
      <%= ff.label :password %><br />
      <%= ff.text_field :password %>
    </div>
  <% end %>
    ...
<% end %>
Valery Kvon
  • 4,438
  • 1
  • 20
  • 15