私はUser
多くを持つことができるを持っていRestaurants
ます。複数のユーザーを持つこともできます。
ユーザーAがレストランAを作成した場合に、同じ名前の別のレストランを作成できないようにするために、これが必要です。
ただし、ユーザーBがレストランAを作成する場合は、許可する必要がありますが、後で別の レストランAを作成することはできません。
私は次のhas_many through
関係を持っています:
restaurant.rb
has_many :ownerships
has_many :users, :through => :ownerships
# This following ensures uniqueness of the name within the
# Restaurants table regardless of who the User is that created it.
validates :name, presence: true, uniqueness: true
user.rb
has_many :ownerships
has_many :restaurants, :through => :ownerships
owner.rb
belongs_to :restaurant
belongs_to :user
私が試したこと
1.:uniqu=>trueを追加します
:uniq => trueをrestaurant.rbファイルに追加してみたので、次のようになります。
has_many :ownerships
has_many :users, :through => :ownerships, :uniq => true
そして、検証から削除uniqueness: true
して、次のようにします。
validates :name, presence: true
しかし、それは何の役にも立ちません。
2.ownership.rb内に検証を追加します
私はそのownership.rb
ようにファイルに検証を追加しようとしました:
validates :restaurant, uniqueness: {:scope => :user}
しかし、私は得ます:
NoMethodError in RestaurantsController#create
undefined method `text?' for nil:NilClass
そして、この検証の範囲内でも、ユーザーの範囲内でレストラン名を探すように指示することはできないようです。
3.before_createコールバック関数の作成
私のrestaurant.rb
ファイルでは、次のように宣言しました。
before_create :check_uniqueness
def check_uniqueness?
user = User.find_by_id(self.user_ids)
isUnique = false
user.restaurants.each do |restaurant|
if !Restaurant.find_by_name(self.name).nil? # Restaurant w/ same now found
isUnique = false
else
isUnique = true
end
return isUnique
end
end
私の仮定では、レストランレコードが作成される前に、このcheck_uniqueness
チェックが実行され、関数がfalseを返した場合、保存されません。
しかし、送信ボタンを押すと、次のエラーが発生します。
NameError in RestaurantsController#create
undefined local variable or method `check_uniqueness' for #<Restaurant:0x007f95a16d10f8>
実用的なソリューション
以下のRobertChuchroの助けのおかげで、検証を機能させることができました。これが私がしたことです:
restaurant.rb
before_create :unique_per_user?
def unique_per_user?
user = User.find_by_id(self.user_ids)
restaurant = user.restaurants.find(:all, :conditions => ["name = ?", self.name])
if restaurant.size > 0
self.errors.add(:name, ": You've already created a restaurant with this name.")
end
return (restaurant.size <= 0)
end