在Rails中使用多个复选框获取TypeMismatch



我正在尝试在Rails中创建一个多复选框选项。

我得到的主要错误是:
ActiveRecord::AssociationTypeMismatch in ContactsController#update
ContactGroup(#114780) expected, got "" which is an instance of String(#2400)

Contact.rb

class Contact < ApplicationRecord
belongs_to :user
has_many :contact_groups
has_many :contact_types
end

ContactGroup.rb

class ContactGroup < ApplicationRecord
belongs_to :user
has_and_belongs_to_many :contacts
end

在Partial:

<div class="col">
<%= form.label :contact_types, style: "display: block" %>
<%= form.collection_check_boxes :contact_types, 
ContactType.all, :id, :name %>
</div>
</div>

注意,通过显示各种复选框,表单确实正确显示了。但是,它不能正确提交。

以下是我在联系人控制器中的联系人参数:

def contact_params
params.require(:contact).permit(:first_name, :last_name, :last_known_country, 
:last_known_city, :mobile_phone_1, :mobile_phone_2, 
:office_phone_1, :office_phone_2, :home_phone, 
:other_phone, :email_1, :email_2, :email_3, 
:email_4, :email_5, :website_1, :website_2, 
:website_3, :website_4, :website_5, :website_6, 
:website_7, :website_8, :contact_apps, :birthday, 
:address_1, :address_2, :how_we_met, :things_I_like, 
:best_memories, :areas_for_improvement, :notes, 
contact_groups:[], contact_types:[])
end

下面是它最终通过表单提交的内容:

"contact_groups"=>["", "1", "2"],
"contact_types"=>["", "1"],

更新行动:

def update
respond_to do |format|
if @contact.update(contact_params)
format.html { redirect_to contact_url(@contact), notice: "Contact was successfully updated." }
format.json { render :show, status: :ok, location: @contact }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @contact.errors, status: :unprocessable_entity }
end
end
end

在提交表单之前,我为联系人组选择了两个选项,并为联系人类型选择了唯一可用的选项。我想这是1,第一行是2,下面是1。但是为什么它也提交一个空字符串呢?如何修改我的代码,使其保存正确?

更新:

以下是我提交新联系人并尝试编辑联系人时的rails日志:

Started POST "/contacts" for ::1 at 2023-04-09 18:37:42 -0400
Processing by ContactsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "contact"=>{"first_name"=>"Monroe", "last_name"=>"Mann", "last_known_country"=>"United States", "last_known_city"=>"Rye", "mobile_phone_1"=>"18084824136", "office_phone_1"=>"", "home_phone"=>"", "email_1"=>"roe@monroemannlaw.com", "website_1"=>"", "contact_apps"=>"", "birthday"=>"", "address_1"=>"54 Cedar PlrnApt 2", "how_we_met"=>"", "things_I_like"=>"", "best_memories"=>"", "areas_for_improvement"=>"", "notes"=>"", "contact_group_ids"=>["", "1"], "contact_type_ids"=>["", "1"], "office_phone_2"=>"", "other_phone"=>"", "email_2"=>"", "email_3"=>"", "email_4"=>"", "email_5"=>"", "website_2"=>"", "website_3"=>"", "website_4"=>"", "website_5"=>"", "website_6"=>"", "website_7"=>"", "website_8"=>"", "mobile_phone_2"=>"", "address_2"=>""}, "commit"=>"Create Contact"}
Unpermitted parameters: :contact_group_ids, :contact_type_ids. Context: { controller: ContactsController, action: create, request: #<ActionDispatch::Request:0x00007f83f16b01f8>, params: {"authenticity_token"=>"[FILTERED]", "contact"=>{"first_name"=>"Monroe", "last_name"=>"Mann", "last_known_country"=>"United States", "last_known_city"=>"Rye", "mobile_phone_1"=>"18084824136", "office_phone_1"=>"", "home_phone"=>"", "email_1"=>"roe@monroemannlaw.com", "website_1"=>"", "contact_apps"=>"", "birthday"=>"", "address_1"=>"54 Cedar PlrnApt 2", "how_we_met"=>"", "things_I_like"=>"", "best_memories"=>"", "areas_for_improvement"=>"", "notes"=>"", "contact_group_ids"=>["", "1"], "contact_type_ids"=>["", "1"], "office_phone_2"=>"", "other_phone"=>"", "email_2"=>"", "email_3"=>"", "email_4"=>"", "email_5"=>"", "website_2"=>"", "website_3"=>"", "website_4"=>"", "website_5"=>"", "website_6"=>"", "website_7"=>"", "website_8"=>"", "mobile_phone_2"=>"", "address_2"=>""}, "commit"=>"Create Contact", "controller"=>"contacts", "action"=>"create"} }
User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
↳ app/controllers/contacts_controller.rb:25:in `create'
TRANSACTION (0.2ms)  BEGIN
↳ app/controllers/contacts_controller.rb:28:in `block in create'
Contact Create (2.3ms)  INSERT INTO "contacts" ("first_name", "last_name", "last_known_country", "last_known_city", "mobile_phone_1", "mobile_phone_2", "office_phone_1", "office_phone_2", "home_phone", "other_phone", "email_1", "email_2", "email_3", "email_4", "email_5", "website_1", "website_2", "website_3", "website_4", "website_5", "website_6", "website_7", "website_8", "contact_apps", "birthday", "address_1", "address_2", "how_we_met", "things_I_like", "best_memories", "areas_for_improvement", "notes", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35) RETURNING "id"  [["first_name", "Monroe"], ["last_name", "Mann"], ["last_known_country", "United States"], ["last_known_city", "Rye"], ["mobile_phone_1", "18084824136"], ["mobile_phone_2", ""], ["office_phone_1", ""], ["office_phone_2", ""], ["home_phone", ""], ["other_phone", ""], ["email_1", "roe@monroemannlaw.com"], ["email_2", ""], ["email_3", ""], ["email_4", ""], ["email_5", ""], ["website_1", ""], ["website_2", ""], ["website_3", ""], ["website_4", ""], ["website_5", ""], ["website_6", ""], ["website_7", ""], ["website_8", ""], ["contact_apps", ""], ["birthday", ""], ["address_1", "54 Cedar PlrnApt 2"], ["address_2", ""], ["how_we_met", ""], ["things_I_like", ""], ["best_memories", ""], ["areas_for_improvement", ""], ["notes", ""], ["created_at", "2023-04-09 22:37:42.257414"], ["updated_at", "2023-04-09 22:37:42.257414"], ["user_id", 1]]

↳ app/controllers/contacts_controller.rb:28:in `block in create'
TRANSACTION (6.3ms)  COMMIT
↳ app/controllers/contacts_controller.rb:28:in `block in create'
Redirected to http://localhost:3000/contacts/3
Completed 302 Found in 25ms (ActiveRecord: 9.0ms | Allocations: 4506)

Started GET "/contacts/3" for ::1 at 2023-04-09 18:37:42 -0400
Processing by ContactsController#show as HTML
Parameters: {"id"=>"3"}
Contact Load (0.4ms)  SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
↳ app/controllers/contacts_controller.rb:64:in `set_contact'
Rendering layout layouts/application.html.erb
Rendering contacts/show.html.erb within layouts/application
Rendered contacts/_contact.html.erb (Duration: 7.7ms | Allocations: 844)
Rendered contacts/show.html.erb within layouts/application (Duration: 19.6ms | Allocations: 1835)
User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
↳ app/views/layouts/_topnav.html.erb:9
Rendered layouts/_logged_in_nav.html.erb (Duration: 1.2ms | Allocations: 280)
Rendered layouts/_topnav.html.erb (Duration: 4.4ms | Allocations: 1127)
Rendered layout layouts/application.html.erb (Duration: 120.7ms | Allocations: 5889)
Completed 200 OK in 131ms (Views: 121.3ms | ActiveRecord: 0.8ms | Allocations: 6860)

Started GET "/contacts/3/edit" for ::1 at 2023-04-09 18:37:52 -0400
Processing by ContactsController#edit as HTML
Parameters: {"id"=>"3"}
Contact Load (0.3ms)  SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
↳ app/controllers/contacts_controller.rb:64:in `set_contact'
Rendering layout layouts/application.html.erb
Rendering contacts/edit.html.erb within layouts/application
ContactGroup Load (0.4ms)  SELECT "contact_groups".* FROM "contact_groups"
↳ app/views/contacts/_form.html.erb:105
Rendered contacts/_form.html.erb (Duration: 8.2ms | Allocations: 7047)
Rendered contacts/edit.html.erb within layouts/application (Duration: 8.6ms | Allocations: 7109)
Rendered layout layouts/application.html.erb (Duration: 9.2ms | Allocations: 7188)
Completed 500 Internal Server Error in 13ms (ActiveRecord: 0.7ms | Allocations: 8010)

ActionView::Template::Error (PG::UndefinedColumn: ERROR:  column contact_groups.contact_id does not exist
LINE 1: ..."contact_groups"."id" FROM "contact_groups" WHERE "contact_g...
^
):
102:
103:           <div class="col">
104:             <%= form.label :contact_groups, style: "display: block" %>
105:             <%= form.collection_check_boxes :contact_group_ids, ContactGroup.all, :id, :name %>
106:             </div>
107:           </div>
108:
app/views/contacts/_form.html.erb:105
app/views/contacts/_form.html.erb:3
app/views/contacts/edit.html.erb:8

你得到一个类型不匹配,因为你将一个id数组分配给contact_groups,它期望一个模型实例数组。

使用contact_group_idscontact_type_ids代替:

<%= form.collection_check_boxes :contact_type_ids, ContactType.all, :id, :name %>

https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html method-i-collection_check_boxes


如果你想在ContactContactGroup之间有多对多的关系,你需要有一个连接表

# db/migrate/*_create_contacts.rb
class CreateContacts < ActiveRecord::Migration[7.0]
def change
create_table :users
create_table :contacts do |t|
t.references :user
end
create_table :contact_groups
# join table
create_table :contact_grouppings do |t|
t.references :contact
t.references :contact_group
end
end
end
# app/models/user.rb                                                                                                                                                       
class User < ApplicationRecord
has_many :contacts
end
# app/models/contact_groupping.rb
class ContactGroupping < ApplicationRecord
belongs_to :contact_group
belongs_to :contact
end
# app/models/contact_group.rb
class ContactGroup < ApplicationRecord
has_many :contact_grouppings, dependent: :destroy
has_many :contacts, through: :contact_grouppings
end
# app/models/contact.rb
class Contact < ApplicationRecord
belongs_to :user
has_many :contact_grouppings, dependent: :destroy
has_many :contact_groups, through: :contact_grouppings
end

现在当你提交contact_group_ids时,它应该更新contact_grouppings连接表:

>> u = User.create
>> u.contacts.create!
>> 3.times { ContactGroup.create! }
>> u.contacts.first.contact_group_ids
=> []
>> u.contacts.first.contact_group_ids = [1]
ContactGroup Load (0.2ms)  SELECT "contact_groups".* FROM "contact_groups" WHERE "contact_groups"."id" = ?  [["id", 1]]
TRANSACTION (0.1ms)  begin transaction
ContactGroupping Create (0.3ms)  INSERT INTO "contact_grouppings" ("contact_id", "contact_group_id") VALUES (?, ?)  [["contact_id", 1], ["contact_group_id", 1]]
TRANSACTION (6.9ms)  commit transaction
=> [1]
>> u.contacts.first.contact_group_ids = [2,3]
ContactGroup Load (0.3ms)  SELECT "contact_groups".* FROM "contact_groups" WHERE "contact_groups"."id" IN (?, ?)  [["id", 2], ["id", 3]]
TRANSACTION (0.0ms)  begin transaction
ContactGroupping Delete All (0.2ms)  DELETE FROM "contact_grouppings" WHERE "contact_grouppings"."contact_id" = ? AND "contact_grouppings"."contact_group_id" = ?  [["contact_id", 1], ["contact_group_id", 1]]
ContactGroupping Create (0.1ms)  INSERT INTO "contact_grouppings" ("contact_id", "contact_group_id") VALUES (?, ?)  [["contact_id", 1], ["contact_group_id", 2]]
ContactGroupping Create (0.1ms)  INSERT INTO "contact_grouppings" ("contact_id", "contact_group_id") VALUES (?, ?)  [["contact_id", 1], ["contact_group_id", 3]]
TRANSACTION (5.0ms)  commit transaction
=> [2, 3]
>> u.contacts.first.contact_groups
=> [#<ContactGroup:0x00007f212cd46530 id: 2>, #<ContactGroup:0x00007f212cd45ea0 id: 3>]

https://guides.rubyonrails.org/association_basics.html the-has-and-belongs-to-many-association

最新更新