Rails最佳实践使用多态关联

时间:2013-09-27 05:28:10

标签: ruby-on-rails params polymorphism

我实际上在我的应用程序中创建了一个分类系统。这是我的表架构:

分类

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

此create方法正确保存数据但是如果你看一下params属性,你会发现对象taxonomies正在等待term_id,但我只能使用{{1在我的形式。感觉有点脏,我想要你的观点,以避免这样的黑客攻击。

另外,我认为这个问题与上面的问题有关,在编辑我的项目时,选中框不会检查与当前帖子关联的实际匹配类别。

欢迎任何想法。

非常感谢

编辑:
这是我的表格

taxonomy_ids

编辑2:
我将= 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' 添加到我的关注中:

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'

但是,当帖子成功保存后,关联不会。任何想法???

编辑3:
在我的控制器中,我添加了这个:

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

提交表单时,我收到以下错误:

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

根据该帖Rails 4 nested form - no implicit conversion of Symbol into Integer,因为我在no implicit conversion of Symbol into Integer 中使用taxonomies_attributes作为:

fields_for

但是,如果我将其删除为:

= f.fields_for :taxonomies_attributes do |taxo|

该块除了包裹div之外什么也没有显示:

= f.fields_for :taxonomies do |taxo|

编辑4:
最后让它有效。选择框未显示的事实来自于创建新资源时,我的<div class="form-group"> <!-- Should be display here but nothing --> </div> 没有分类法。执行以下操作修复:

@post

感谢所有人

1 个答案:

答案 0 :(得分:2)

我不确定我是否完全理解你的问题,但我注意到的一件事是你真的不需要分两步保存。

只需将以下行添加到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使用了正确的嵌套 - 我不确定,因为您没有发布表单代码。