has_many :through Association, NoMethodError (undefined method `each' for "":String) 并保存关联

has_many :through Association, NoMethodError (undefined method `each' for "":String) and save association

我无法让 has_many :through Association 工作。我是否需要在 post_controller 的创建方法中设置一些额外的东西来保存 post_category? (在代码下方,错误和我的尝试)

我有一个 has_many :through Association with post, post_category 和 as join table 分类如下:

Post模特:

class Post < ApplicationRecord
  has_many :categorizations
  has_many :post_categories, :through => :categorizations
end

Post::Category 模型(使用命名空间以获得更好的项目结构):

class Post::Category < ApplicationRecord
  has_many :categorizations
  has_many :posts, :through => :categorizations
end

分类模型(使用 class_name,Post::Category 命名空间的原因):

class Categorization < ApplicationRecord
  belongs_to :post
  belongs_to :post_category, :class_name => 'Post::Category'
end

然后我在 select 视图中创建了 post 和 post_category:

<div class="form-group">
  <%= f.label :post_categories, :class => 'control-label', :value => 'Category: ' %>
  <%= f.select :post_categories, options_from_collection_for_select(all_post_categories, :id, :name), {}, {class: 'selectpicker', :'data-live-search' => 'true', required: 'false' } %>
</div>

在posts_controller中,我允许:post_categories符号:

def post_params
  params.require(:post).permit(:post_categories)
end

这是我的协会迁移文件:

class CreateCategorizations < ActiveRecord::Migration[5.0]
  def change
    create_table :categorizations do |t|
      t.integer :post_id
      t.integer :post_category_id

      t.timestamps
    end
    add_index :categorizations, :post_id
    add_index :categorizations, :post_category_id
    # multiple-key index enforces uniqueness on (post_id, post_category_id)
    # pairs, so that a category can't have the same post twice
    add_index :categorizations, [:post_id, :post_category_id], unique: true
  end
end

当我尝试提交表单时,我在日志中收到以下错误:

NoMethodError (undefined method `each' for "3":String):
app/controllers/posts_controller.rb:32:in `create'

所以我搜索了一些答案 ok -> .

我尝试了另一种方法让协会继续运作。

所以我尝试使用 post_category_id,就像推荐的那样 here

我在视图select中设置

<%= f.select :post_category_id, options_from_collection_for_select(all_post_categories, :id, :name), {}, {class: 'selectpicker', :'data-live-search' => 'true', required: 'false' } %>

然后在 posts_controller 允许 category_id:

def post_params
  params.require(:post).permit(:post_category_id)
end

并且在 Post 模型中:

class Post < ApplicationRecord
  has_many :categorizations
  has_many :post_category_id, :through => :categorizations
end

这是新错误:

Could not find the source association(s) "post_category_id" or :post_category_id in model Categorization. Try 'has_many :post_category_id, :through => :categorizations, :source => <name>'. Is it one of post or post_category?

好的,因为没有 post_category_id 关联。

更新:

post_params:

<ActionController::Parameters {"content"=>"content", "post_categories"=>"2"} permitted: true>

我认为你需要改变这个:

<%= f.select :post_categories, options_from_collection_for_select(all_post_categories, :id, :name), {}, {class: 'selectpicker', :'data-live-search' => 'true', required: 'false' } %>

对此:

  <%= f.select :post_categories[:id],
  options_from_collection_for_select(all_post_categories, :id, :name), 
  class: 'selectpicker', :'data-live-search' => 'true', required: 'false' , include_hidden: false} %>

如果我错了就开枪吧。

已编辑:根据 SO 4585355

为 rails 4.2+ 添加 hidden:false

我找到了一个适合我的解决方案answer and this question

第一个解决方案只用 Post

保存一个 Post::Category

关于这个 answer,我不得不将 posts_controller 中的许可参数更改为:

def post_params
  params.require(:post).permit(:post_category_ids)
end

然后我还需要在创建 post 和 post_category 的视图中将 select 更改为:

<div class="form-group">
  <%= f.label :post_category_ids, :class => 'control-label', :value => 'Category: ' %>
  <%= f.select :post_category_ids, options_from_collection_for_select(all_post_categories, :id, :name), {}, {class: 'selectpicker', :'data-live-search' => 'true', required: 'false' } %>
</div>

就是这样。其余代码仍然与我在第二次尝试问题之前显示的相同。

第二个解决方案用Post

保存多个Post::Category

关于这个 question,我需要将 posts_controller 中的许可参数更改为:

def post_params
  params.require(:post).permit(:post_category_ids => [])
end

并且要同时select多个Post::Category,我需要在视图中的select中添加multiple: 'true'

<div class="form-group">
  <%= f.label :post_category_ids, :class => 'control-label', :value => 'Category: ' %>
  <%= f.select :post_category_ids, options_from_collection_for_select(all_post_categories, :id, :name), {}, {class: 'selectpicker', :'data-live-search' => 'true', required: 'false', multiple: 'true' } %>
</div>