如何使用collection_select创建多态模型?

时间:2010-05-11 16:37:55

标签: ruby-on-rails forms polymorphic-associations

这是我的模特:

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  

我现在要做的是这样的事情: 应用程序/视图/会话/ 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 %>

但由于多态分配,它无法正常工作。我该如何处理这个问题?

编辑: 错误是:

undefined method `base_class' for String:Class

以params为:

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

传递给speakable的价值是演讲者/公司的ID。是的,这是我指定要返回collection_select的值,但我如何设法提供这两个值(speakable_idspeakable_type)?

2 个答案:

答案 0 :(得分:1)

您可以使用hidden_field保存speakable_type。这样,每次所选选项更改时,您都必须更改hidden_field的值。我不确定这是最好的方法,但有效......

希望它对你有所帮助。

修改

您必须在选择中定义:onchange选项。

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

hidden_fieldnil值开头。

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

您的setSpeakableType()函数必须设置正确的speakable_type

答案 1 :(得分:0)

我解决了这个问题的两种方法。

第一种是在表单中处理你的集合,这样你就可以确定id的开头类型。类似的东西:

       

      
                    

  

然后在你的控制器动作中:

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

第二种是使用javascript来更改隐藏在页面中的隐藏字段speakable_type和speakable_id。我最终使用自动填充器来填充此字段,因此在进行选择时调用javascript非常简单。第二种方法使控制器更强大批次