Лучшая практика Rails для использования полиморфной ассоциации

Я фактически создаю систему таксономии в своем приложении. Вот моя схема таблиц:

Taxonomies

class CreateTaxonomies < ActiveRecord::Migration
 def change
 create_table :taxonomies do |t|
 t.references :taxonomable, polymorphic: true
 t.integer :term_id
 end
 end
end

сроки

class CreateTerms < ActiveRecord::Migration
 def change
 create_table :terms do |t|
 t.string :name
 t.string :type
 t.integer :parent_id, default: 0
 end
 end
end

и вот мои ассоциации:

class Taxonomy < ActiveRecord::Base
 belongs_to :taxonomable, polymorphic: true
end

class Term < ActiveRecord::Base
 self.inheritance_column = :_type_disabled // because I use type as table field
 has_many :taxonomies, as: :taxonomable
end

Чтобы сделать его более общим, я вызываю беспокойство:

module Taxonomable
 extend ActiveSupport::Concern

 included do
 has_many :taxonomies, as: :taxonomable
 end

 def get_associate_terms
 terms = self.taxonomies.map { |t| t.term_id }
 taxonomies = Term.find terms
 end
end

и я включаю его в свою модель:

class Post < ActiveRecord::Base
 include Taxonomable
end

Он отлично работает, и я могу получить связанные данные с помощью get_associate_terms. Моя проблема находится внутри моего контроллера и моей формы. Я фактически сохраняю это так:

# posts/_form.html.haml
= f.select :taxonomy_ids, @categories.map { |c| [c.name, c.id] }, {}, class: 'form-control'

# PostsController
def create
 @post = current_user.posts.new( post_params )
 if @post.save
 @post.taxonomies.create( term_id: params[:post][:taxonomy_ids] )
 redirect_to posts_path
 else
 render :new
 end
end

Этот метод создания правильно сохраняет данные, но если вы посмотрите на атрибут params, вы увидите, что taxonomies объектов ждут term_id но я могу использовать taxonomy_ids в моей форме. Это кажется грязным, и я хотел, чтобы ваша точка зрения не позволяла так взломать.

Кроме того, и я думаю, что эта проблема связана с той, что была выше, при редактировании моего элемента в поле выбора не проверяется, что фактическая соответствующая категория ассоциируется с текущим сообщением.

Любые мысли приветствуются.

большое спасибо

РЕДАКТИРОВАТЬ: Вот моя форма

= form_for @post, url: posts_path, html: { multipart: true } do |f|
 = f.select :taxonomy_ids, @categories.map { |c| [c.name, c.id] }, {}, class: 'form-control'

EDIT 2: Я добавил accepts_nested_attributes_for к моей заботе, так как он:

module Taxonomable
 include do
 has_many :taxonomies, as: :taxonomable, dependent: :destroy
 accepts_nested_attributes_for :taxonomies
 end
end

а затем использовать fields_for в моей форме:

= f.fields_for :taxonomies_attributes do |taxo|
 = taxo.label :term_id, 'Categories'
 = taxo.select :term_id, @categories.map { |c| [c.name, c.id] }, {}, class: 'form-control'

При отправке формы я получаю ее:

"post"=>{"type"=>"blog", "taxonomies_attributes"=>{"term_id"=>"2"}, "reference"=>"TGKHLKJ-567TYGJGK", "name"=>"My super post"

Однако, когда сообщение было успешно сохранено, ассоциации не являются. Есть идеи???

ИЗМЕНИТЬ 3: В моем контроллере я добавил следующее:

def post_params
 params.require(:post).permit(
 taxonomies_attributes: [:term_id]
 )
end

При отправке формы у меня появляется следующая ошибка:

no implicit conversion of Symbol into Integer

Согласно этой записи Rails 4 вложенной формы - не подразумевается преобразование символа в Integer, потому что я использую taxonomies_attributes в своих fields_for как:

= f.fields_for :taxonomies_attributes do |taxo|

Однако, если я удалю его:

= f.fields_for :taxonomies do |taxo|

Блок ничего не отображает, кроме обрезания div:

<div>
 <!-- Should be display here but nothing -->
</div>

EDIT 4: Наконец, это сработает. Тот факт, что окно выбора не показывалось, @post тем, что при создании нового ресурса мой @post не имеет таксономий. Выполнение следующего исправления, которое:

def new
 @product = current_user.products.new
 category = @product.taxonomies.build
end

Спасибо всем

1 ответ

Я не уверен, полностью ли я понимаю ваш вопрос, но одна вещь, которую я заметил, это то, что вам не нужно сохранять в два шага.

Просто добавьте следующую строку в модуль Taxonomable (Rails 3)

attr_accessible :taxonomies_attributes
accepts_nested_attributes_for :taxonomies

Если вы используете Rails 4, добавьте только accepts_nested_attributes_for в ваш модуль Taxonomable и каждый из контроллеров, убедитесь, что атрибуты таксономий разрешены. Например, в вашем PostsController добавьте следующее к вашему

def post_params
 params.require(:post).permit(:name, taxonomies_attributes: [:name])
 end

Ваше создание изменится на:

def create
 @post = current_user.posts.new( post_params )
 if @post.save
 redirect_to posts_path
 else
 render :new
 end
end

Это предполагает, что ваша форма использует правильное вложение через fields_for Я не уверен в этом, поскольку вы не опубликовали код формы.

licensed under cc by-sa 3.0 with attribution.