【问题标题】:has_many :through Association, NoMethodError (undefined method `each' for "":String) and save associationhas_many :through Association, NoMethodError (undefined method `each' for "":String) 并保存关联
【发布时间】:2026-02-08 11:05:02
【问题描述】:

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

我有一个 has_many :through 关联 post、post_category 和 as join table 分类如下:

帖子模型:

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

帖子::类别模型(使用命名空间以获得更好的项目结构):

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

然后我在视图中有一个选择,我在其中创建带有 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 -> You can't assign string to association.

我尝试了另一种方法来使关联发挥作用。

所以我尝试使用 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>

【问题讨论】:

  • 你真的希望这个has_many :post_category_id, :through =&gt; :categorizations 工作吗?
  • @AndreyDeineko 这是一次尝试,表明我尝试了另一种方法。是的,但最终肯定行不通
  • 您可以在创建帖子时从创建操作中添加参数(来自日志)吗? (进行初始设置时)
  • 是的,更新了问题@AndreyDeineko
  • 我的意思是错误。我想看看,传递了什么——也许在那里我们可以找到错误的根源。所以需要更大的日志:)

标签: ruby-on-rails ruby has-many-through nomethoderror


【解决方案1】:

我通过answerquestion 找到了适合我的解决方案。

第一个只保存一个 Post::Category 的解决方案

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

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

然后我还需要将创建帖子的视图中的选择更改为:

<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::Category 的第二种解决方案

关于这个question,我需要把posts_controller中的permit参数改成这个:

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

并且要同时选择多个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>

【讨论】:

    【解决方案2】:

    我认为你需要改变这个:

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

    【讨论】:

    • 谢谢,但现在我收到错误 no implicit conversion of Symbol into Integer
    • 尝试使用'post_categories[id]'
    • 还是不行,undefined local variable or method id