开发者

How do I create a polymorphic model with a collection_select?

This 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  

What I want to do now is something like this: 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 is not working because of the polymorphic assignment. How do I approach this problem?

EDIT: The Error is:

undefined method `base_class' for String:Class

with params being:

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

The value passed to speakable is the id of the Speaker/Company. Yes, this is the value I specified the collection_select to return, but how can I manage to supply both values (speakable_id and speakable_type) ?


You can use a hidden_field to save the speakable_type. This way you'll have to change the value of the hidden_field every time the selected option changes. I'm not sure this is the best approach, but works...

Hope it helps you.

Edit

You'll have to define the :onchange option in your select.

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

The hidden_field starts with nil value.

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

And your setSpeakableType() function will have to set the proper speakable_type.


Two ways I've solved this.

The first is to munge your collection in the form, so that you can figure out which type the id is to begin 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 to use javascript to change the hidden fields speakable_type and speakable_id which are hidden in the page. I ended up using an autocompleter to fill out this field, so invoking javascript when a selection was made was easy enough. The second way makes the controller a lot cleaner.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜