2017-07-20 17 views
1

私は2つの関連するモデルに施行一意性制約を持つための最良の方法は、私が欲しいの両方なし主キーRailsの一意性制約

class Parent > ApplicationRecord 
    has_many :children 
    :name 
end 

class Child > ApplicationRecord 
    :name 
end 

ませんレールの属性を知りたいですその(parent.name、child.name)がすべての親に対して一意であることを強制する。例えば

  • (parent1, child1)(parent2, child1)
  • (parent1, child1)(parent1, child1)は理想的

違反で許可されている、しかし私は、私が唯一の複数の列に一意性制約を追加するためのオプションを見てきました、Postgresの中でこれを強制う同じテーブル。

また、レールのカスタムバリデータを書いていますが、これは迷惑です。より良い解決策が必要です。

完全性のために、子供のリストを返すモデルにchildren関数を追加するために必要な制約バリデータです。

def children 
    {children: :children} 
end 

移行(Parent.rb中)

class NamePairValidator < ActiveModel::Validator 
    def validate(record) 
    record.children.values.each do |model_children| 
     names = model_children.to_a.collect {|model| model.name} 
     if (names.select{|name| names.count(name) > 1 }.size > 0) 
     record.errors[:name] << 'Path leading to this resource has no unique name' 
     end 
    end 
    end 
end 

は:

class CreateDomains < ActiveRecord::Migration[5.0] 
    def change 
    create_table :domains do |t| 
     t.string :name 
     t.string :domain_type 
     t.timestamps 
    end 
    end 
end 

class CreateSubjects < ActiveRecord::Migration[5.0] 
    def change 
    create_table :subjects do |t| 
     t.string  :name 
     t.string  :subject_type 
     t.timestamps 
    end 
    end 
end 

class CreateJoinTableDomainSubject < ActiveRecord::Migration[5.0] 
    def change 
    create_join_table :domains, :subjects do |t| 
     t.index [:domain_id, :subject_id] 
     t.index [:subject_id, :domain_id] 
    end 
    end 
end 
+0

両方のモデルの移行ファイルの書き方を表示できますか? DBレベルでの整合性を保証するためのインデックスを追加することもできます。たとえば、https://robots.thoughtbot.com/the-perils-of-uniqueness-validations –

+0

データベースレベルでこれを行うには、変更することができます'parent_id'カラムと' child_id'カラムを 'parent_name'カラムと' child_name'カラムに追加し、独自の制約を追加します。いくつかのActiveRecordハッカーでは、これらの列を外部キーとして使用することができます。私はこの解決策について単なる考えではないと思います。 – Ptr

+0

Thx!私はあなたがピボットテーブルを持っていると思います!だから、Nithinの答えはうまくいかない。このリンクをご覧ください:http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association。それは構文と関係であなたを助けるかもしれません –

答えて

1

私はちょうど私のコードに類似したものを使用

validates :child_name, uniqueness: { scope: :parent_id } 

もっと...

(I)https://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of

(ⅱ)Validate uniqueness of multiple columns

+0

を明確にするために、どのモデルでこの検証(Parent、Child)を追加しますか? –

+0

'child'モデル、' child_name'も例ですattr – Nithin

+0

okay cool - deleted – gwalshington

0

のRuby on Railsの公式ドキュメントのthe-has-many-through-associationによってInsipered:

class CreateAppointments < ActiveRecord::Migration[5.0] 
    def change 
    create_table :domains do |t| 
     t.string :name, null: false 
     t.string :domain_type 
     t.timestamps 
    end 

    create_table :subjects do |t| 
     t.string  :name, null: false 
     t.string  :subject_type 
     t.timestamps 
    end 

    create_table :fields do |t| 
     t.belongs_to :domain, index: true 
     t.belongs_to :subject, index: true 
     t.timestamps 
    end 
    end 
end 

  • 私が撮りましたあなたのモデルの名前を変更するイニシアチブもっと読むことができるように3210によってField

  • また、nameフィールドには、一意性を確認するためにnilを指定しないでください。

今専用のクラス(移行ファイル内のnull: falseとの両方のモデルでvalidates :name, presence: true追加):

class Subject < ApplicationRecord 
    has_many :fields 
    has_many :domains, through: :fields 

    validates :name, presence: true 
end 

class Domain < ApplicationRecord 
    has_many :fields 
    has_many :subjects, through: :fields 

    validates :name, presence: true 
end 

class Field < ApplicationRecord 
    belongs_to :domain 
    belongs_to :subject 

    validate :domain_and_subject_names_uniqueness 

    private 

    def domain_and_subject_names_uniqueness 
    if class.includes(:domain, subject) 
      .where(domain: { name: domain.name }, subject: { name: subject.name }) 
      .exists? 
     errors.add :field, 'duplicity on names' 
    end 
    end 
end 

モデルが関連しているので、私は与えられたFieldDomainモデルにアクセスするためにField.first.domainを使用することができますがその逆の場合はです。

+0

ドメインに件名を追加する使用法が変更されました。私はした: '@domain.subjects << Subject.new(params) @ domain.save'。これはもう動作しないようです... –

+0

エラーは何ですか?私のコードを適用しようとしましたか? –

+0

はい。このエラーが発生しました: 'NoMethodError in SubjectsController#create' #のための'未定義メソッドsubject_name '#あなたは 'meanですか? subject' –