How can I create a polymorphic model using collection_select?

These are my models:

class Speaker < ActiveRecord::Base
  belongs_to :session, :foreign_key => :session_id, :class_name => :Session
  belongs_to :speakable, :polymorphic => true
end  

class Session < ActiveRecord::Base
  has_many :speakers
  accepts_nested_attributes_for :speakers
end

class Person < ActiveRecord::Base
  has_many :speakers, :as => :speakable
end       

class Company < ActiveRecord::Base
  has_many :speakers, :as => :speakable
end  

      

Now I want to do the following: app / views / sessions / edit.html.erb

  <% f.fields_for :speakers do |sf| %>
    <p>
      <%= sf.label :speaker %><br />
      <%= sf.collection_select :speakable, Company.all + Person.all, :id, :full_name %>  
    </p>
  <% end %>

      

But it doesn't work because of the polymorphic assignment. How can I approach this problem?

EDIT: Error:

undefined method `base_class' for String:Class

      

with parameters:

"speaker"=>{"speakable"=>"1063885469", "session_id"=>"1007692731"}

      

The value passed in as the speaker is the Speaker / Company identifier. Yes, it's a value that I have to go back collection_select

, but I can manage two values ( speakable_id

and speakable_type

)?

+2


a source to share


2 answers


I solved it two ways.

The first is to create your collection on the form so you can define what type the identifier should start with. Something similar to this:

  

    

              



And then in your controller action:

def action
  if params[:speaker][:speakable].begins_with?("Person:")
     speak_type = 'Person'
     speak_id = params[:speaker][:speakable].split(":")[1].to_i
  elsif params[:speaker][:speakable].begins_with?("Company:")
     speak_type = 'Company'
     speak_id = params[:speaker][:speakable].split(":")[1].to_i
  end
  params[:speaker].delete(:speakable)
  obj = Speaker.new(params[:speaker])
  obj.speaker_type = speak_type
  obj.speaker_id = speak_id
  ... rest of action ... 
end

      

The second is using javascript to change the hidden speakable_type and sayable_id fields that are hidden on the page. I ended up using autocomplete to fill in this field, so the javascript reference for the selection was easy enough. The second way makes the controller a clean lot .

0


a source


You can use hidden_field

to save speakable_type

. Thus, you will have to change the value hidden_field

every time the selected parameter changes. I'm not sure if this is the best approach, but it works ...

Hope this helps you.

Edit

You need to define an option :onchange

in your choice.



<%= sf.collection_select :speakable, Company.all + Person.all, :id, 
   :full_name, {}, {:onchange => "setSpeakableType()"} %>  

      

hidden_field

starts with a value nil

.

<%= sf.hidden_field :speakable_type, :value => nil %>

      

And your function setSpeakableType()

should set the correct one speakable_type

.

+1


a source







All Articles