Question

I have an association of Item & Category through Categorization:

class Item < ActiveRecord::Base
  has_many :categorizations
  has_many :categories, :through => :categorizations, :source => :category
end


class Category < ActiveRecord::Base
  has_many :categorizations
  has_many :items, :through => :categorizations, :source => :item
  attr_accessible :name
end

class Categorization < ActiveRecord::Base
  belongs_to :item
  belongs_to :category
end

Items/new:

<div class="container">
<%= render 'shared/error_create_item_messages'%>
<br/>

<%= form_for(@item, :html => {:multipart => true} ) do |f| %>

    <div class="clearfix">      
       <label>
         <%= f.label :name %>
      </label>
      <div class="input">       
         <%= f.text_field :name %>
      </div>
    </div>


     <div class="clearfix">
        <label>
         <%= f.label :category %>
        </label>

        <%= hidden_field_tag "product[category_ids][ ]", nil %>     
        <% Category.all.each do |category| %>
          <div class="input">           
               <%= check_box_tag "item[category_ids][ ]", category.id, 
                                            @item.category_ids.include?(category.id) %>
              <%= category.name %>
          </div>    
         <% end %>
     </div>     

     <div class="action">
        <div class="btn_create_item_align">
        <%= f.submit "Create item", :class=>"btn primary" %>
        </div>
     </div>

<% end %>
</div>

Categorizations_controller

class CategorizationsController < ApplicationController
   def create
     @categories = Category.all
     Categorization.create(:item_id => item.id, :category_id => category.id)
     Categorization.save
   end

  def edit
  end

end

Items_controller

def create
    @item = @current_user.items.build(params[:item])
    @categories = Category.all
    if @item.save
      redirect_to @item
    else
      render 'new'
    end
 end

The problem is When i hit save (create Item), and i check the Categorization table and check the on console, The items saved still dont have category_id. So the new item and its attributes (name, description, price) is saved to DB properly, but NOT the category. It wont save to db.

Any ideas? (Newbie in Rails) Thanks

Was it helpful?

Solution

The form POSTs to ItemsController#create, and CategorizationsController#create isn't being called (you can verify this with some puts debugging).

You can use accepts_nested_attributes_for to have the Item's create action do all the work. The trick is to only create Category associations whose boxes are checked, and you can do that with the :reject_if option (see Rails API doc for more info):

app/models/item.rb:

class Item < ActiveRecord::Base
  has_many :categorizations
  has_many :categories, :through => :categorizations, :source => :category
  accepts_nested_attributes_for :categories, 
                                :reject_if => proc{|c| c[:persist].blank?}
end

Then you can create form fields for the nested objects, one checkbox per category.

app/views/items/new.html.erb:

<%= form_for @item do |f| %>
  <%# stuff to generate item fields... %>

  <%= f.fields_for :categories do |cat| %>
    <%= cat.check_box :persist %>
    <%= cat.label :name, cat.name %>
  <%- end %>

  <%# submit button, etc. %>
<%- end %>

Populate the set of Categories to choose from when creating a new Item by building (but not saving) Categories associated with the Item. This is effectively moving code from your view to the controller:

app/controllers/items_controller.rb:

def new  
  @item = Item.new  
  Category.all.each {|cat| @item.categories.build(cat.attributes) }  
end

It'll be educational to puts the params in that controller action, so you can see what the hashes being sent from the form look like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top