Reputation: 23
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
Upvotes: 2
Views: 447
Reputation: 3542
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.
Upvotes: 1