Как мне создать полиморфную модель с collection_select? - PullRequest
2 голосов
/ 11 мая 2010

Это мои модели:

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 %>

Но это не работает из-за полиморфного присваивания. Как мне подойти к этой проблеме?

EDIT: Ошибка:

undefined method `base_class' for String:Class

с параметрами:

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

Значение, передаваемое говорящему, является идентификатором докладчика / компании. Да, это значение, которое я указал для collection_select для возврата, но как мне обеспечить оба значения (speakable_id и speakable_type)?

Ответы [ 2 ]

1 голос
/ 11 мая 2010

Вы можете использовать hidden_field для сохранения speakable_type. Таким образом, вам придется менять значение hidden_field каждый раз, когда изменяется выбранный параметр. Я не уверен, что это лучший подход, но работает ...

Надеюсь, это поможет вам.

Редактировать

Вам нужно будет определить опцию :onchange в вашем выборе.

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

hidden_field начинается со значения nil.

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

И ваша setSpeakableType() функция должна будет установить правильное значение speakable_type.

0 голосов
/ 11 мая 2010

Я решил это двумя способами.

Первое - это разобрать вашу коллекцию в форме, чтобы вы могли выяснить, с какого типа идентификатор должен начинаться. Нечто похожее на это:


А потом в вашем контроллере действие:

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 при выборе было достаточно просто. Второй способ делает контроллер много чище.

...