Ruby on Rails: 在表单上为另一个模型添加表单
Ruby on Rails: Add form for another model on a form
在 Ruby 的 Rails 应用程序中,我试图实现组和联系人之间的关系,一个组可以包含多个联系人,一个联系人可以属于多个组。我正在使用一个名为 Contactgroup 的模型来处理这种关系,因此 table 是:
Group (id, name)
Contact (id, firstname, surname)
Contactgroup (group_id, contact_id)
示例数据为:
Groups:
ID Name
1 Singers
2 Drummers
Contacts:
ID Firstname Surname
1 Freddy Mercury
2 Roger Taylor
3 Kurt Cobain
4 Dave Grohl
Contact Groups:
Group_ID Contact_ID
1 1
1 3
1 4
2 2
2 4
我想要做的是获取它,以便当用户创建群组时,他们可以 select 他们想要添加到该群组的联系人。这意味着有一个组表单,用户可以在其中键入组名,在这个表单上,我想为每个用户的联系人显示复选框,以便用户可以 select 他们想要添加的联系人组,当他们单击提交时,新组将保存在组 table 中,新的联系人组记录将保存在联系人组 table.
中
这是app/views/groups/_form.html.erb
代码:
<%= form_for @group do |f| %>
<% if @group.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@group.errors.count, "error") %> prohibited this group from being saved:
</h2>
<ul>
<% @group.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<h2>Add members:</h2>
<%= form_for([@group, @group.contactgroups.build]) do |f| %>
<p>
<%= f.collection_check_boxes(:contact_id, @contacts, :id, :firstname) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
在这里你可以看到我正在尝试使用的代码:
<h2>Add members:</h2>
<%= form_for([@group, @group.contactgroups.build]) do |f| %>
<p>
<%= f.collection_check_boxes(:contact_id, @contacts, :id, :firstname) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
我从 rails 指南 (http://guides.rubyonrails.org/getting_started.html) 那里得到了这个,但是我收到错误 undefined method
contactgroups' for #` 并且认为这不会给我想要的东西.
我的路线文件是:
Rails.application.routes.draw do
get 'sessions/new'
get 'sessions/create'
get 'sessions/destroy'
resources :users
get 'welcome/index'
root 'welcome#index'
resources :contacts
resources :groups do
resources :contactgroups
end
resources :contactgroups
get 'sessions/new'
get 'sessions/create'
get 'sessions/destroy'
controller :sessions do
get 'login' => :new
post 'login' => :create
get 'logout' => :destroy
end
end
我的groups_controller:
class GroupsController < ApplicationController
def index
@groups = Group.where(user_id: session[:user_id])
end
def show
@group = Group.find(params[:id])
@members = Contactgroup.where(group_id: @group.id)
end
def new
@group = Group.new
@contacts = Contact.where(user_id: session[:user_id])
end
def edit
@group = Group.find(params[:id])
end
def create
@group = Group.new(group_params)
@group.user_id = session[:user_id]
if @group.save
redirect_to @group
else
render 'new'
end
end
def update
@group = Group.find(params[:id])
if @group.update(group_params)
redirect_to @group
else
render 'edit'
end
end
def destroy
@group = Group.find(params[:id])
@group.destroy
redirect_to groups_path
end
private
def group_params
params.require(:group).permit(:name, :user_id)
end
end
并联系groups_controller:
class ContactgroupsController < ApplicationController
def destroy
@contactgroup = Contactgroup.find(params[:id])
@contactgroup.destroy
redirect_to(:back)
end
end
我的模型如下:
Contact.rb
:
class Contact < ActiveRecord::Base
end
Group.rb
:
class Group < ActiveRecord::Base
end
Contactgroup.rb
:
class Contactgroup < ActiveRecord::Base
belongs_to :contact
belongs_to :group
end
必须有一个简单的解决方案来解决这个问题,因为我认为它通常在其他系统上完成,但我不确定如何做到这一点。
有人可以帮忙吗。
您不能在表单中使用表单。 collection_check_boxes
的正确使用方法如下。
替换
<%= form_for([@group, @group.contactgroups.build]) do |f| %>
<p>
<%= f.collection_check_boxes(:contact_id, @contacts, :id, :firstname) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
只有
<p>
<%= f.collection_check_boxes(:contact_ids, @contacts, :id, :firstname) %>
</p>
好的,问题很简单。您正在调用 @group.contactgroups
,但实际上您还没有在 group
模型上设置该关联。仅从 contactgroup
方建立关联。所以你可以 contactgroup.group
但不能 group.contactgroups
你最好的选择是将其实际建模为 habtm - 正如我之前提到的。您可以这样做:
Contact.rb:
class Contact < ActiveRecord::Base
has_and_belongs_to_many :groups
end
Group.rb:
class Group < ActiveRecord::Base
has_and_belongs_to_many :contacts
end
注意:您仍然有 HABTM 联系人组的概念,但使用 Rails 标准命名,它将在您的数据库中作为 contacts_groups
table。然后你就可以那样构建你的表单了。
快速 google,这里有一个关于在 HABTM 中使用复选框的 S/O 问题(尚未审查它是否对您的情况有用):Rails 4 - checkboxes for has_and_belongs_to_many association
使用 HABTM 是 Rails 标准做法,原因有很多。它确实确实适合您的情况(老实说!)并且它实际上并没有违反您希望在 SQL 中看到它的要求(说真的!)。
先试一试:)
我可以告诉您如何打破 Rails 约定...但通常众所周知,在您了解约定的用途之前,您不应该打破约定。
这比最初 thought/suggested 简单多了。
我需要做的是将模型更改为:
Contactgroup
belongs_to :contact
belongs_to :group
Contact
has_many :contactgroups
has_many :groups, through: :contactgroups, :dependent => :destroy
Group
has_many :contactgroups
has_many :contacts, through: :contactgroups, :dependent => :destroy
在 groups_controller
中,我需要将新方法和参数更改为:
def new
@group = Group.new
@group.contactgroups.build
end
private
def group_params
params.require(:group).permit(:name, :user_id, { contact_ids: [] })
end
然后将下面这行代码添加到app/views/groups/_form.html.erb
中:
<%= f.collection_check_boxes :contact_ids, Contact.where(user_id: session[:user_id]), :id, :firstname ,{ prompt: "firstname" } %>
这为我提供了每个联系人的复选框,并允许从组表单创建联系人组记录。
在 Ruby 的 Rails 应用程序中,我试图实现组和联系人之间的关系,一个组可以包含多个联系人,一个联系人可以属于多个组。我正在使用一个名为 Contactgroup 的模型来处理这种关系,因此 table 是:
Group (id, name)
Contact (id, firstname, surname)
Contactgroup (group_id, contact_id)
示例数据为:
Groups:
ID Name
1 Singers
2 Drummers
Contacts:
ID Firstname Surname
1 Freddy Mercury
2 Roger Taylor
3 Kurt Cobain
4 Dave Grohl
Contact Groups:
Group_ID Contact_ID
1 1
1 3
1 4
2 2
2 4
我想要做的是获取它,以便当用户创建群组时,他们可以 select 他们想要添加到该群组的联系人。这意味着有一个组表单,用户可以在其中键入组名,在这个表单上,我想为每个用户的联系人显示复选框,以便用户可以 select 他们想要添加的联系人组,当他们单击提交时,新组将保存在组 table 中,新的联系人组记录将保存在联系人组 table.
中这是app/views/groups/_form.html.erb
代码:
<%= form_for @group do |f| %>
<% if @group.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@group.errors.count, "error") %> prohibited this group from being saved:
</h2>
<ul>
<% @group.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<h2>Add members:</h2>
<%= form_for([@group, @group.contactgroups.build]) do |f| %>
<p>
<%= f.collection_check_boxes(:contact_id, @contacts, :id, :firstname) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
在这里你可以看到我正在尝试使用的代码:
<h2>Add members:</h2>
<%= form_for([@group, @group.contactgroups.build]) do |f| %>
<p>
<%= f.collection_check_boxes(:contact_id, @contacts, :id, :firstname) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
我从 rails 指南 (http://guides.rubyonrails.org/getting_started.html) 那里得到了这个,但是我收到错误 undefined method
contactgroups' for #` 并且认为这不会给我想要的东西.
我的路线文件是:
Rails.application.routes.draw do
get 'sessions/new'
get 'sessions/create'
get 'sessions/destroy'
resources :users
get 'welcome/index'
root 'welcome#index'
resources :contacts
resources :groups do
resources :contactgroups
end
resources :contactgroups
get 'sessions/new'
get 'sessions/create'
get 'sessions/destroy'
controller :sessions do
get 'login' => :new
post 'login' => :create
get 'logout' => :destroy
end
end
我的groups_controller:
class GroupsController < ApplicationController
def index
@groups = Group.where(user_id: session[:user_id])
end
def show
@group = Group.find(params[:id])
@members = Contactgroup.where(group_id: @group.id)
end
def new
@group = Group.new
@contacts = Contact.where(user_id: session[:user_id])
end
def edit
@group = Group.find(params[:id])
end
def create
@group = Group.new(group_params)
@group.user_id = session[:user_id]
if @group.save
redirect_to @group
else
render 'new'
end
end
def update
@group = Group.find(params[:id])
if @group.update(group_params)
redirect_to @group
else
render 'edit'
end
end
def destroy
@group = Group.find(params[:id])
@group.destroy
redirect_to groups_path
end
private
def group_params
params.require(:group).permit(:name, :user_id)
end
end
并联系groups_controller:
class ContactgroupsController < ApplicationController
def destroy
@contactgroup = Contactgroup.find(params[:id])
@contactgroup.destroy
redirect_to(:back)
end
end
我的模型如下:
Contact.rb
:
class Contact < ActiveRecord::Base
end
Group.rb
:
class Group < ActiveRecord::Base
end
Contactgroup.rb
:
class Contactgroup < ActiveRecord::Base
belongs_to :contact
belongs_to :group
end
必须有一个简单的解决方案来解决这个问题,因为我认为它通常在其他系统上完成,但我不确定如何做到这一点。
有人可以帮忙吗。
您不能在表单中使用表单。 collection_check_boxes
的正确使用方法如下。
替换
<%= form_for([@group, @group.contactgroups.build]) do |f| %>
<p>
<%= f.collection_check_boxes(:contact_id, @contacts, :id, :firstname) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
只有
<p>
<%= f.collection_check_boxes(:contact_ids, @contacts, :id, :firstname) %>
</p>
好的,问题很简单。您正在调用 @group.contactgroups
,但实际上您还没有在 group
模型上设置该关联。仅从 contactgroup
方建立关联。所以你可以 contactgroup.group
但不能 group.contactgroups
你最好的选择是将其实际建模为 habtm - 正如我之前提到的。您可以这样做:
Contact.rb:
class Contact < ActiveRecord::Base
has_and_belongs_to_many :groups
end
Group.rb:
class Group < ActiveRecord::Base
has_and_belongs_to_many :contacts
end
注意:您仍然有 HABTM 联系人组的概念,但使用 Rails 标准命名,它将在您的数据库中作为 contacts_groups
table。然后你就可以那样构建你的表单了。
快速 google,这里有一个关于在 HABTM 中使用复选框的 S/O 问题(尚未审查它是否对您的情况有用):Rails 4 - checkboxes for has_and_belongs_to_many association
使用 HABTM 是 Rails 标准做法,原因有很多。它确实确实适合您的情况(老实说!)并且它实际上并没有违反您希望在 SQL 中看到它的要求(说真的!)。
先试一试:) 我可以告诉您如何打破 Rails 约定...但通常众所周知,在您了解约定的用途之前,您不应该打破约定。
这比最初 thought/suggested 简单多了。
我需要做的是将模型更改为:
Contactgroup
belongs_to :contact
belongs_to :group
Contact
has_many :contactgroups
has_many :groups, through: :contactgroups, :dependent => :destroy
Group
has_many :contactgroups
has_many :contacts, through: :contactgroups, :dependent => :destroy
在 groups_controller
中,我需要将新方法和参数更改为:
def new
@group = Group.new
@group.contactgroups.build
end
private
def group_params
params.require(:group).permit(:name, :user_id, { contact_ids: [] })
end
然后将下面这行代码添加到app/views/groups/_form.html.erb
中:
<%= f.collection_check_boxes :contact_ids, Contact.where(user_id: session[:user_id]), :id, :firstname ,{ prompt: "firstname" } %>
这为我提供了每个联系人的复选框,并允许从组表单创建联系人组记录。