【问题标题】:Ruby on Rails: Add form for another model on a formRuby on Rails:为表单上的另一个模型添加表单
【发布时间】:2017-05-24 04:40:44
【问题描述】:

在我的 Ruby on Rails 应用程序中,我试图实现 Group 和 Contact 之间的关系,一个组可以包含多个联系人,一个联系人可以是多个组的一部分。我正在使用一个名为 Contactgroup 的模型来处理这种关系,所以表格是:

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

我想要做的是得到它,这样当用户创建一个组时,他们可以选择他们想要添加到该组的联系人。这意味着存在组表单,用户可以在其中键入组名称,并且在此表单上,我想为每个用户的联系人显示复选框,以便用户可以选择他们想要添加到组中的联系人,以及何时他们点击提交新组将保存在组表中,新的联系人组记录将保存在联系人组表中。

这是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 guides (http://guides.rubyonrails.org/getting_started.html) 得到了这个,但我收到了错误 undefined methodcontactgroups' 的 #` 并且不认为这会给我想要的东西。

我的路线文件是:

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

还有contactgroups_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

必须有一个简单的解决方案来解决这个问题,因为我假设它通常在其他系统上完成,但我不知道如何做到这一点。

有人可以帮忙吗。

【问题讨论】:

  • 有一个“在 Rails 中连接表”和“拥有并属于许多”的 google - Rails 为您提供了很好的帮助方法,这意味着您不必自己手动处理连接表(即你所谓的Contactgroup 是为你处理的)。还要查看“嵌套资源”和“嵌套表单”。同样,rails 也有一些很好的帮手为您完成繁重的工作:)
  • @TarynEast 感谢您的评论。我知道 Rails 有很多关系并且属于许多关系,这可以在 Ruby 中完成,但为了它的透明度,我想使用连接表。我会谷歌嵌套表单,因为我认为这是我想要的?
  • 只是好奇:重用 rails 已经编写的用于处理此问题的代码是否更加透明? :)
  • 因为我可以在 SQL 浏览器中实际看到数据,只是让错误检查更容易
  • 我可能没有说得很好,我的意思是我认为将记录保存在一个表格中的不同模型的表格中是很常见的

标签: ruby-on-rails ruby forms ruby-on-rails-3 ruby-on-rails-4


【解决方案1】:

这比最初想象/建议的要简单得多。

我需要做的是将模型更改为:

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" } %>

这为我提供了每个联系人的复选框,并允许从组表单创建联系人组记录。

【讨论】:

    【解决方案2】:

    好的,所以问题很简单。您正在调用@group.contactgroups,但您实际上还没有在group 模型上设置该关联。仅从contactgroup 端设置关联。所以你可以做contactgroup.group 但不能做group.contactgroups

    您最好的选择是将其实际建模为 habtm - 正如我之前提到的。你会这样做:

    联系方式.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 表。然后你可以用这种方式构建你的表单。

    通过快速谷歌搜索,这里有一个关于在 HABTM 中使用复选框的 S/O 问题(尚未审查它是否对您的情况有用):Rails 4 - checkboxes for has_and_belongs_to_many association

    使用 HABTM 是 Rails 的标准做法,有很多很好的理由。它确实确实适合您的情况(老实说!),并且实际上并没有打破您希望在 SQL 中看到它的要求(说真的!)。

    先试试看 :) 我可以告诉你如何打破 Rails 的约定……但一般都知道,在你知道约定的用途之前,你不应该打破约定。

    【讨论】:

      【解决方案3】:

      您不能在表单中使用表单。 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>
      

      【讨论】:

      • 或者使用fields_for 而不是form_for(绝对删除额外的提交):)
      • 抱歉,您能解释一下这是如何工作的吗?我知道&lt;%= f.collection_check_boxes(:contact_ids, @contacts, :id, :firstname) %&gt; 行应该为每个联系人显示复选框,但我不明白如何为每个选定的联系人添加新的联系人组记录?
      • 这将发送数组中的所有 id 键 contact_ids,如 contact_ids = [1,2,3,4,5]。并将其分配给组对象就可以了。 apidock.com/rails/v4.0.2/ActionView/Helpers/FormOptionsHelper/…
      • @PriyankGupta 感谢您的评论,但这不能工作,因为联系人和组模型之间没有关系,因为这是通过联系人组模型完成的,所以它不能 @ 987654330@
      • 您可以从组中为has_many :contacts, through: :contacts_groups创建关联
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-16
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多