【问题标题】:Join table with composite key in rails在rails中使用复合键连接表
【发布时间】:2013-03-22 21:14:14
【问题描述】:

让我们假设 User 和 Company 模型之间有一个通用连接表 FollowCompany,例如:

class FollowCompany < ActiveRecord::Base
  attr_accessible :user_id, :company_id

  belongs_to :user
  belongs_to :company

end

它有一个复合主键 [user_id, company_id]。 它没有 id 列,因为 follow_company 记录由 [used_id, company_id] 唯一标识

由于我希望能够将以下关系视为资源,因此我将其设为 RESTful:

routes.rb:

resources :follow_companies

然而,这会导致一个问题:这些生成的路由假设一个我没有的 :id 键。 如何告诉 rails 我实际上使用的是复合键?

我能想到四种解决方案,我想就哪一种最好提供一些意见:

  1. 不要将 :follow_companies 设为资源。相反,将 URL 与两个键模式匹配:例如:match '/follow_companies/:user_id/:company_id/' =&gt; follow_companies#edit 然而,这很丑,因为它很冗长而不是 RESTful。

  2. 覆盖 FollowCompany to_param 方法以包含两个模型 ID,例如

    def to_param
     "#{user_id},#{company_id}"
    end
    

    但是这很丑,因为它看起来像一个 hack,并且有一些令人讨厌的副作用

  3. 将主键列添加到 follow_company 表。 然而,这很丑陋,因为它增加了冗余。 follow_company 记录由 [company_id, user_id] 唯一标识。无需额外的密钥。

  4. 下载复合键 gem 并将其与我的开发环境集成。 然而,这很丑陋,因为它不是标准方式并且与其他 ruby​​ 代码不兼容。

所以,如您所见,我想不出一个优雅的解决方案。 这似乎是一种常见的情况,尽管我不能成为第一个遇到这种情况的人。几乎每个应用程序都使用(restful)连接表。 处理此问题的最佳做法是什么?

【问题讨论】:

    标签: ruby-on-rails routes composite-primary-key jointable


    【解决方案1】:

    数字 3 的优点是您的密钥将毫无意义。虽然不适用于您的情况,但如果某个键值由于某种原因需要更改,则使用复合键会导致该资源的 URL 发生更改。创建一个无意义的主键意味着即使数据发生变化,URL 也会保持不变。

    这也往往是连接表的“Rails 方式”。

    【讨论】:

    • +1 是的,还有许多其他充分的理由来拥有一个没有商业价值的主键。更多信息stackoverflow.com/a/8777574/631619
    • 好的,同意。但这不是通过引入冗余来使表非规范化吗?现在我不得不担心重复,例如用户两次关注同一家公司。甚至可以插入一条 (id,NULL,NULL) 记录,表明没有人关注任何公司。为了防止这样的废话,我将不得不使用约束。在我看来,额外的 id 列似乎增加了很多复杂性和令人头疼的问题,而不是让事情变得更容易。这真的是首选方式吗?
    • 是的,您可以拥有 (id, NULL, NULL) 或重复,但您当然可以使用 validates_presence 和 valid_uniqueness :id1, scope: :id2 验证这些东西
    • 当没有连接表的模型时,`validated_uniqueness :id1, scope: :id2` 去哪儿了?另外,rails api中似乎没有任何名为validated_uniqueness的方法。
    • @gwho validates_uniqueness 是我相信的 Rails 2 语法。结帐guides.rubyonrails.org/… 了解当前的执行方式。
    【解决方案2】:

    我对 ActiveRecord 没有那么自信,但为什么要使用组合键?当然,您所描述的是 many_to_many 连接。那么这行不通:

    class User < ActiveRecord::Base
      has_many :follow_companies
      has_many :companies, through: :follow_companies
    end
    
    class FollowCompany < ActiveRecord::Base
      belongs_to :user
      belongs_to :company
    end
    
    class Company < ActiveRecord::Base
      has_many :follow_companies
    end
    

    这意味着您可以像这样以嵌套路由的形式直接路由到公司:

    resources :users do
      collection :follow_companies
    end
    

    这会给你像'/users/1/follow_companies'这样的路线,在你的控制器中你可以这样做:

    class UsersController < ApplicationController
      def follow_companies
        @user = User.find(params[:id])
        @companies = @user.companies
      end
    end
    

    或者类似的?

    【讨论】:

      猜你喜欢
      • 2016-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 2015-02-20
      • 2017-10-25
      相关资源
      最近更新 更多