Only one out of the two reference ID's is being set in one of my tables.
schema
Models
tech.rb
class Tech < ActiveRecord::Base
has_many :services
end
service_menu
class ServiceMenu < ActiveRecord::Base
has_many :services
end
service.rb
class Service < ActiveRecord::Base
belongs_to :tech
belongs_to :service_menu
end
Controller
services_controller.rb
def new
@service = current_tech.services.build
end
def create
@service = current_tech.services.build(service_params)
respond_to do |format|
if @service.save
format.html { redirect_to @service, notice: 'Service was successfully created.' }
format.json { render :show, status: :created, location: @service }
else
format.html { render :new }
format.json { render json: @service.errors, status: :unprocessable_entity }
end
end
end
private
def service_params
params.require(:service).permit(:name)
end
View
<%= simple_form_for @service do |f| %>
<div class="field">
<%= f.label "Select service category" %>
<br>
<%= collection_select(:service, :name, ServiceMenu.all, :name, :name, {:prompt => true }) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Whenever I create a new service, only the tech_id is recorded but not the service_menu_id. How can I create a new service that would record both tech and service_menu ids at once to the services table?
Any help is appreciated.
EDIT 7/3 2:55 PM EST
@Yen-Ju method didn't work for me at first but now it does. At first I've failed to properly reference the service_menu_id
in the services table
.
My services
db before:
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| tech_id | int(11) | YES | MUL | NULL | |
| service_menu_id | int(11) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+-----------------+--------------+------+-----+---------+----------------+
Reason for not working before is there was no MUL
value under the KEY
column.
My services
db now:
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| tech_id | int(11) | YES | MUL | NULL | |
| service_menu_id | int(11) | YES | MUL | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+-----------------+--------------+------+-----+---------+----------------+
This also allowed me to drop the name
column in the services
db since it's no longer needed.
Thanks to all who responded.
You need to add has_many :through
relationships to your models:
tech.rb
class Tech < ActiveRecord::Base
has_many :services
has_many :service_menus, through: :services
end
service_menu.rb
class ServiceMenu < ActiveRecord::Base
has_many :services
has_many :techs, through: :services
end
service.rb
class Service < ActiveRecord::Base
belongs_to :tech
belongs_to :service_menu
end
Once you do this, Active Record takes care of the join model (Service) housekeeping for you. You can demonstrate this in the Rails console:
>> tech = Tech.create(name: "bar")
(0.2ms) begin transaction
SQL (0.4ms) INSERT INTO "techs" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "bar"], ["created_at", "2015-07-03 23:30:26.893615"], ["updated_at", "2015-07-03 23:30:26.893615"]]
(10.7ms) commit transaction
=> #<Tech id: 4, name: "bar", created_at: "2015-07-03 23:30:26", updated_at: "2015-07-03 23:30:26">
>> tech.service_menus << ServiceMenu.create(name: "baz")
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "service_menus" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "baz"], ["created_at", "2015-07-03 23:31:21.045841"], ["updated_at", "2015-07-03 23:31:21.045841"]]
(18.9ms) commit transaction
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "services" ("tech_id", "service_menu_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["tech_id", 4], ["service_menu_id", 4], ["created_at", "2015-07-03 23:31:21.072932"], ["updated_at", "2015-07-03 23:31:21.072932"]]
(33.1ms) commit transaction
ServiceMenu Load (0.3ms) SELECT "service_menus".* FROM "service_menus" INNER JOIN "services" ON "service_menus"."id" = "services"."service_menu_id" WHERE "services"."tech_id" = ? [["tech_id", 4]]
=> #<ActiveRecord::Associations::CollectionProxy [#<ServiceMenu id: 4, name: "baz", created_at: "2015-07-03 23:31:21", updated_at: "2015-07-03 23:31:21">]>
>> Service.first
Service Load (0.4ms) SELECT "services".* FROM "services" ORDER BY "services"."id" ASC LIMIT 1
=> #<Service id: 2, tech_id: 4, service_menu_id: 4, created_at: "2015-07-03 23:31:21", updated_at: "2015-07-03 23:31:21">`
I did not test the code, but this might work.
First, change your view to set service_menu_id
<%= collection_select(:service, :service_menu_id, ServiceMenu.all, :id, :name, {:prompt => true }) %>
Second, in your controller, allow service_menu_id to pass:
def service_params
params.require(:service).permit(:service_menu_id)
end
Then, when you build your service, the service_menu_id will be passed successfully.
You need to do the following changes.
Add service_menu_id
in your servuce_params
.
def service_params
params.require(:service).permit(:name, :service_menu_id)
end
And change your view code like this
<%= simple_form_for @service do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label "Select service category" %>
<br>
<%= collection_select(:service, :service_menu_id, ServiceMenu.all, :name, :name, {:prompt => true }) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If you use postrgesql, you could read this ActiveRecord documentation in 1.6 Composite Types
and use composite types
for Your task.
For example:
CREATE TYPE full_service_id AS
(
tech_id INTEGER,
service_menu_id_ INTEGER
);
# db/migrate/20140207133952_create_services.rb
execute <<-SQL
CREATE TYPE full_service_id AS
(
tech_id INTEGER,
service_menu_id_ INTEGER
);
SQL
create_table :services do |t|
t.column full_service_id
end
# app/models/service.rb
class Service < ActiveRecord::Base
belongs_to :tech, foreign_key: 'full_service_id.tech_id'
belongs_to :service_menu, foreign_key: 'full_service_id.service_menu_id_'
end
# Usage
Service.create full_service_id: "#{tech_id},#{service_menu_id_}"
service = Service.first
service.full_service_id # => "(1,1)"
service.full_service_id = "(2,2)"
service.save!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.