2

I can't get the has_many :through Association to work. And do I need to set something extra in the create method from the post_controller, to save also the post_category? (Below the code, the errors and my tries)

I have a has_many :through Association with post, post_category and as join table categorization as follows:

The Post Model:

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

The Post::Category Model (Used namespacing for better project structure):

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

The Categorization Model (Used class_name, cause of the namespacing of Post::Category):

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

And then I have in the view a select where I create a post with a 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>

In the posts_controller, I permitted the :post_categories symbol:

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

Here is my migration file for the Association:

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

When I try to submit the form, I get the following error in the logs:

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

So I searched for some answers ok -> You can't assign string to association.

I tried another way to make the association going to work.

So I tried using the post_category_id, like recommended here

I set in the select of the view

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

then in the posts_controller permit the category_id:

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

and in the Post model:

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

This is the new error:

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?

Ok makes sense, cause there is no post_category_id association.

Update:

The post_params:

<ActionController::Parameters {"content"=>"content", "post_categories"=>"2"} permitted: true>
Community
  • 1
  • 1
ronatory
  • 7,156
  • 4
  • 29
  • 49
  • do you really expect this `has_many :post_category_id, :through => :categorizations` to work? – Andrey Deineko Sep 20 '16 at 20:33
  • @AndreyDeineko It was a try, to show that I tried another approach. Yes but in the end it will definitely not work – ronatory Sep 20 '16 at 20:38
  • could you add the params (from logs) from create action when you create post? (When having an initial setup) – Andrey Deineko Sep 20 '16 at 20:54
  • yes, updated the question @AndreyDeineko – ronatory Sep 20 '16 at 20:58
  • i meant along with the error. I wanted to see, what was passed - may be there we can find the source of error. So bigger piece of logs needed :) – Andrey Deineko Sep 20 '16 at 21:00
  • sry maybe I understand you wrong. This is what I get in the logs `Processing by PostsController#create as JS Parameters: {"utf8"=>"✓", "authenticity_token"=>"rKM0Owc+uNDMlB63nPMa/nggszVffejp/YGJxkPldpTlJAzIhTGo3+LMuzmFAM2Ca3CProJVTAvkpbLgJRgNUw==", "post"=>{"post_categories"=>"2", "content"=>"film film"}}` – ronatory Sep 20 '16 at 21:09

2 Answers2

1

I figured out a right solution for me with this answer and this question.

First solution to just save one Post::Category with a Post

Regarding to this answer, I had to change my permit parameter in the posts_controller to this:

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

Then I need also to change the select in the view where I create a post with a post_category to this:

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

That's it. The rest of the code is still the same as I showed before my second try in my question.

Second solution to save multiple Post::Category with a Post

Regarding to this question, I need to change my permit parameter in the posts_controller to this:

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

And to select more than one Post::Category at the same time, I need to add multiple: 'true' to the select in the view:

<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>
Community
  • 1
  • 1
ronatory
  • 7,156
  • 4
  • 29
  • 49
0

I think you need to change this:

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

to this:

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

Shoot me if I'm wrong.

Edited: include hidden:false for rails 4.2+ as per SO 4585355

Community
  • 1
  • 1
Andy Gauge
  • 1,428
  • 2
  • 14
  • 25