Как я могу элегантно построить форму для модели, которая имеет полиморфную ассоциацию? - PullRequest
4 голосов
/ 11 июля 2011

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

class Lesson < ActiveRecord::Base
  belongs_to :topic, :polymorphic => true  
  validates_presence_of :topic_type, :topic_id  
end

class Subject < ActiveRecord::Base  
   has_many :lessons, :as => :topic  
end

class Category < ActiveRecord::Base  
  has_many :lessons, :as => :topic  
end

Теперь мне нужна форма, которая позволит пользователю создавать или обновлять уроки.Вопрос в том, как я могу предоставить меню выбора, которое предлагает сочетание предметов и категорий?(Для пользователя в данной конкретной форме Предметы и Категории являются взаимозаменяемыми, но в другом месте это не так.)

В идеале это будет выглядеть примерно так:

views / examples / _form.html.haml

= simple_form_for(@lesson) do |f|
  = f.input :title
  = f.association :topic, :collection => (@subjects + @categories)

Это не сработает, потому что мы будем указывать только topic_id, а также нам нужны topic_types.Но как мы можем указать эти значения?

Полагаю, суть проблемы в том, что мне действительно нужно одно меню выбора, в котором указаны два значения, соответствующие двум разным атрибутам (topic_id и topic_type).Есть ли какой-нибудь изящный безрассудный способ сделать это?

Несколько замечаний:

a) Наследование одной таблицы устранит эту проблему, но я бы хотел этого избежать, так как Категории иСубъекты имеют свои собственные отношения ... Я избавлю вас от подробностей.

б) Я мог бы вытащить некоторые javascript махинации, да?Но это звучит грязно, и если есть более чистый способ сделать это, какой-нибудь помощник в магической форме или что-то в этом роде, то это, безусловно, предпочтительнее.

c) Хотя я использую simple_form, я не предан этому,на случай, если это усложнит дело.

Спасибо

Ответы [ 2 ]

0 голосов
/ 17 сентября 2013

Подумав об этом, менее грязная реализация IMO будет заключаться в том, чтобы нанять махинации JS (b):

= f.input_field :topic_type, as: :hidden, class: 'topic_type'
- (@subjects + @categories).each do |topic|
  = f.radio_button :topic_id, topic.id, {:'data-type' => topic.class.name, class: 'topic_id'}

С небольшим количеством JS (ваши потребности могут отличаться):

$('input:radio.topic_id').change(function() {
  $('input:hidden.topic_type').val($(this).attr('data-type'));
});

Примечания:

  • Я использую переключатель, чтобы выбрать тему (категорию или тему) в списке
  • Имя класса каждой из возможных тем хранится ватрибут 'data-type'
  • При выборе переключателя имя класса копируется в скрытый ввод через JS
  • Использование: HTML5, jQuery, haml, simple_form
0 голосов
/ 11 июля 2011

Если вы не хотите использовать STI, вы можете сделать нечто похожее: создать новую модель Topic(name:string), которая будет полиморфно ссылаться на Subject или Category.

class Lesson < ActiveRecord::Base
  belongs_to :topic
  validates_presence_of :topic_id  
end

class Topic < ActiveRecord::Base
  belongs_to :topicable, :polymorphic => true
end

class Subject < ActiveRecord::Base
   has_one :topic, :as => :topicable
   has_many :lessons, :through => :topic
   accepts_nested_attributes_for :topic
end

class Category < ActiveRecord::Base  
   has_one :topic, :as => :topicable
   has_many :lessons, :through => :topic
   accepts_nested_attributes_for :topic
end

В представлениигде вы создаете новую тему / категорию:

<%= form_for @subject do |subject_form| %>
  <%= subject_form.fields_for :topic do |topic_fields| %>
    <%= topic_fields.text_field :name %>
  <% end %>
<% end %>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...