连接表上的附加外键

时间:2016-03-29 21:50:42

标签: mysql ruby-on-rails ruby

我有一个加入客户端和Setor(复数:setores)模型的连接表。关系是客户端has_and_belongs_to_many Setores(有三个Setores,一个Client可以有一个到三个SetSet。Setores有很多客户端。)

我的问题是: 在此连接表中,我添加了对User模型的引用。 Setores有许多用户,但是一个客户端和一个setor之间的关系只有一个用户。但我不知道如何在clients_setores表上读取和写入此关联。

我的模型如下:

class Client < ActiveRecord::Base
has_and_belongs_to_many :documents
has_and_belongs_to_many :setores
has_many :screenings
has_many :contacts
has_many :interactions, through: :contacts
validates :cnpj, uniqueness: true


class Setor < ActiveRecord::Base
  self.table_name = 'setores'
  has_many :documents
  has_many :screenings
  has_many :users
  has_and_belongs_to_many :clients
  attr_acessor :user_id


class User < ActiveRecord::Base
has_one :setores
has_many :clients

当前的连接表参数在客户端控制器的末尾显示如下:

  private
# Use callbacks to share common setup or constraints between actions.
def set_client
  @client = Client.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def client_params
  params.require(:client).permit(:cnpj, :pacote, :razsoc, :vencimento, user_ids:[], document_ids:[], setor_ids:[])
end

请注意,“user_ids:[]”是我试图让它工作的方法,到目前为止已失败。

在视图中,我使用当前的连接表(取自/client/_form.html.erb):

<%= f.collection_check_boxes :setor_ids, Setor.where(pacote: true), :id, :setor do |b| %>

因此,使用这些复选框,我可以在clients_setores表中创建一个条目。

我想做的事情是能够从下拉菜单中选择属于给定setor_id的用户,并将此关系存储在连接表中。我确实设法使用以下代码显示这样的菜单,在同一个_form.html.erb中:

<%= f.collection_select :user_ids, User.where(:setor_id => 1), :id, :email %>

但是当我提交表单时,不会保存这些值。我不知道我的问题是否只是因为我没有在我的视图中记录这种关联的正确方法,或者我的问题是在控制器(可能)和模型(可能)中进一步下降。

我在SO中找到的最近的问题是Rails 4 Accessing Join Table Attributes,但是关联类型不同(has_many / through)并且没有涉及第三个关系,所以我无法弄清楚如何让它工作我

2 个答案:

答案 0 :(得分:1)

三个模型之间的多对多关联示例,使用单个连接表完成:

我从生成一些模型开始:

rails g model User; rails g model Setor; rails g model Client;
rails g model Joiner user_id:integer setor_id:integer client_id:integer

顺便说一句,references是一种添加引用现有模型的外键的方法。即user:references将创建user_id列。它还为外键添加了“索引”,从而提高了性能。

然后我在类

中添加了一些关联
class Joiner
  # columns: user_id, setor_id, client_id
  belongs_to :user
  belongs_to :setor
  belongs_to :client
end

class User
  has_many :joiners
  has_many :setors, through: :joiners, source: :setor
  has_many :clients, through: :joiners, source: :client
end

class Setor
  has_many :joiners
  has_many :users, through: :joiners, source: :user
  has_many :clients, through: :joiners, source: :client
end

class Client
  has_many :joiners
  has_many :users, through: :joiners, source: :user
  has_many :setors, through: :joiners, source: :setor
end

通过编写此代码,您可以获得三种模型的多对多关联。

然后你可以写:

User.create; Setor.create;
Joiner.create(user_id: User.first.id, setor_id: Setor.first.id);
User.first.setors.length # => 1

顺便提一下,这不适用于自连接(即嵌套注释系统),但这不是问题的一部分。

答案 1 :(得分:0)

我最终为实现预期效果而做的是向客户端模型添加三列:

userset1

userset2

userset3

根据他所服务的Setores(部门),客户最多有三个(因为该字段可以为空白)与用户的关系。

这是最简单的解决方案在这种情况下,因为我只有3个Setores。它不会是更大的数字。

如果我有超过3个Setores,让继续在Client表中添加列是不切实际的,我会专门设置一个新模型来存储关系,在这种情况下,除了它的唯一ID之外,还有一个表, client_id,setor_id和user_id。