I'm new to rails and building a relational database application.
I have a somewhat complex database structure, and am trying to create a nested form that creates a child object, and then associates that child object to existing objects through a habtm relationship.
My goal is to make entering data into this database as streamlined as possible. I used Railscast #196-197 to get this far.
Partial Database Structure:
category <-- habtm --> service <-- belongs_to --> provider
Categories have many services, services may be in many categories.
Providers have many services, services belong to a single provider.
Providers may have services in many different categories.
Models:
class Provider < ActiveRecord::Base
has_many :services, :dependent => :destroy
accepts_nested_attributes_for :services, allow_destroy: true
end
class Service < ActiveRecord::Base
belongs_to :provider
has_and_belongs_to_many :categories
has_many :comments
end
I have a nested form that allows me to add a service from the same form where I am adding a provider.
I have also generated a list of categories (check boxes) to allow the user to associate the service with categories.
The problem is that when I submit the form, the join table for services_categories is not being created.
This is the information from the console that I am getting when I submit my "Create Provider" form. I can see where the category_ids[] are being stored, but they're not being passed anywhere and they aren't initiating the creation of entries in the join table.
Console Printout:
Started POST "/providers" for ::1 at 2015-05-06 14:38:36 -0700
Processing by ProvidersController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"MJXUbLeh+pT3OSC6B2pfGnsUOBkG1
jim2GUpKD9KC72vp3trLAc4Zf+ICZ6yGLiagTGQXMsJ/j8iDpbpCBhUxQ==", "provider"=>{"name
"=>".Test Provider", "organization"=>".Test Organization", "contact"=>"", "phone
"=>"", "website"=>"", "address1"=>"", "address2"=>"", "city"=>"", "state"=>"Onli
ne", "zip"=>"", "services_attributes"=>{"0"=>{"title"=>".Test Service", "descrip
tion"=>"", "_destroy"=>"0"}}}, "category"=>{"service_ids"=>[""]}, "service"=>{"c
ategory_ids"=>["4", "37", "36"]}, "commit"=>"Create Provider"}
(0.0ms) begin transaction
SQL (2.0ms) INSERT INTO "providers" ("name", "organization", "address1", "add
ress2", "city", "state", "phone", "website", "contact", "created_at", "updated_a
t") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["name", ".Test Provider"], ["org
anization", ".Test Organization"], ["address1", ""], ["address2", ""], ["city",
""], ["state", "Online"], ["phone", ""], ["website", ""], ["contact", ""], ["cre
ated_at", "2015-05-06 21:38:36.715129"], ["updated_at", "2015-05-06 21:38:36.715
129"]]
SQL (0.0ms) INSERT INTO "services" ("title", "description", "provider_id", "c
reated_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["title", ".Test Service"], [
"description", ""], ["provider_id", 56], ["created_at", "2015-05-06 21:38:36.731
130"], ["updated_at", "2015-05-06 21:38:36.731130"]]
(39.0ms) commit transaction
Redirected to http://localhost:3000/providers/56
Completed 302 Found in 84ms (ActiveRecord: 41.0ms)
My providers_controller.rb (With some irrelevant parts taken out):
class ProvidersController < ApplicationController
###
def new
@provider = Provider.new
@provider.services.build
@services = Service.all
@service = Service.new
end
def edit
@provider = Provider.find(params[:id])
end
def create
@provider = Provider.new(provider_params)
if @provider.save
redirect_to @provider
else
render 'new'
end
end
###
def get_all_categories
@categories = Category.find(:all, :order => 'name')
end
private
def provider_params
params.require(:provider).permit(:name, :organization, :address1, :address2, :city, :state, :zip, :phone, :website, :contact, :service_ids => [], services_attributes: [:id, :title, :description, :_destroy, :category_ids => []])
end
end
As you can see, the attribute :category_ids =>[] isn't showing up in the list of service attributes in the console.
The relevant parts of the form that I am using to submit provider data:
<%= form_for @provider do |f| %>
<%= f.fields_for :services do |builder| %>
<%= render "services_fields", :f => builder %>
<% end %>
<%= f.submit %>
The form partial for Add New Service:
<%= f.label :title, "Service Title" %><br/>
<%= f.text_field :title %> <br/>
<%= f.label :description, "Service Description" %><br/>
<%= f.text_area :description, :rows => 3 %> <br/>
<p>
<label>Associated Categories</label>
<p>
<label>Associated Categories</label>
<div>
<%= hidden_field_tag "category[service_ids][]", nil %>
<% Category.all.sort_by{|category| category.name}.each do |category| %>
<%= check_box_tag "service[category_ids][]", category.id,
@service.categories.include?(category), id: dom_id(category) %>
<%= label_tag dom_id(category), category.name %></br>
</div>
<% end %>
</p>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Service" %><br/>
I'm interested in any way that you can think of to be able to
- Add Provider
- Add Service
- Associate Service and Category
all in one form.
I have thought about having a pop-up window to take the user to the original Add Service form, which associates Categories, but I'm new to Rails, and I don't know how difficult that would be. I also feel like I ought to be able to do it all on one page.
I am pretty set on having a habtm relationship between Service and Categories. It works well for all other parts of the app.
Please let me know if I can post any other relevant code snippets. Thanks!