我有一个account model
和一个open hours model
。我已经安装了cocoon gem,并且在创建帐户时也添加了营业时间。一切工作正常,除了...。当我有同一天时,在两个字段上打开和关闭小时,而不是抛出验证错误,而是在数据库中两次创建相同的对象。关于如何验证我是否具有同一天同一天在另一个领域的营业时间的任何想法?
class Account < ApplicationRecord
has_many :open_hours
accepts_nested_attributes_for :open_hours, reject_if: :all_blank, allow_destroy: true
end
class OpenHour < ApplicationRecord
belongs_to :account
validates_presence_of :day, :closes, :opens
validates_inclusion_of :day, :in => 1..7
validate :opens_before_closes
validate :valid_from_before_valid_through
validates_uniqueness_of :opens, scope: [:account_id, :day]
validates_uniqueness_of :closes, scope: [:account_id, :day]
protected
def opens_before_closes
errors.add(:closes, ". You have chosen the wrong hours or none at all!") if opens && closes && opens >= closes
end
def valid_from_before_valid_through
errors.add(:valid_through, ". You have chosen the wrong hours or none at all!") if valid_from && valid_through && valid_from >= valid_through
end
end
这是开放时间表:
create_table "open_hours", force: :cascade do |t|
t.integer "account_id"
t.integer "day"
t.time "opens"
t.time "closes"
t.datetime "valid_from"
t.datetime "valid_through"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
这是我创建帐户后发布的内容:
Started PATCH "/accounts/11" for 127.0.0.1 at 2019-01-14 21:18:22 +0200
Processing by AccountsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ENcVLQEa0y1Ppl+b2n1tSlCdzcVcY25p3hIPeipflxO3sUa1EbDc0Vnf+W5SS2TWamNE972LSP+ngDB2eEYRhg==",
"account"=>{"name"=>"Sample 2", "street"=>"421 E DRACHMAN", "street_2"=>"", "city"=>"TUCSON", "state"=>"AZ", "postal_code"=>"85705-7598",
"country"=>"USA", "phone"=>"3023694209", "web_address"=>"www.sample2.com", "category_id"=>["", "5", "10", "13"], "open_hours_attributes"=>{"0"=>{"day"=>"1",
"opens(1i)"=>"2000", "opens(2i)"=>"1", "opens(3i)"=>"1", "opens(4i)"=>"00", "opens(5i)"=>"00", "closes(1i)"=>"2000", "closes(2i)"=>"1", "closes(3i)"=>"1",
"closes(4i)"=>"01", "closes(5i)"=>"00", "account_id"=>"#<Account:0x00007fd029cc1720>", "_destroy"=>"false", "id"=>"1"}, "1"=>{"day"=>"2", "opens(1i)"=>"2000",
"opens(2i)"=>"1", "opens(3i)"=>"1", "opens(4i)"=>"00", "opens(5i)"=>"00", "closes(1i)"=>"2000", "closes(2i)"=>"1", "closes(3i)"=>"1", "closes(4i)"=>"01",
"closes(5i)"=>"00", "account_id"=>"#<Account:0x00007fd029cc1720>", "_destroy"=>"false", "id"=>"2"}}}, "commit"=>"Update Account", "id"=>"11"}
Account Load (0.4ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 11], ["LIMIT", 1]]
答案 0 :(得分:0)
我为此找到的唯一解决方案如下。如果有人认为有更好的方法可以实现此目的,请告诉我。
我将以下代码放入account.rb
def validate_unique_open_hours
validate_uniqueness_of_in_memory(open_hours, [:day, :opens, :closes])
end
def validate_uniqueness_of_in_memory(collection, attrs)
hashes = collection.inject({}) do |hash, record|
key = attrs.map {|a| record.send(a).to_s }.join
if key.blank? || record.marked_for_destruction?
key = record.object_id
end
hash[key] = record unless hash[key]
hash
end
if collection.length > hashes.length
errors.add(:open_hours, "Duplicate values in one or more fields")
end
end
答案 1 :(得分:0)
我只是建议扩大您的unless
语句的使用范围,以使其更具可读性,也许将人为错误消息修改为第二个变量
def validate_uniqueness_of_in_memory(collection, attrs)
hashes = collection.inject({}) do |hash, record|
key = attrs.map {|a| record.send(a).to_s }.join
key = record.object_id unless key.blank? || record.marked_for_destruction?
hash[key] = record unless hash[key]
hash # can't recall if you actually need this as block returns whole self
end
msg = "Duplicate values in one or more fields"
errors.add(:open_hours, msg) if collection.length > hashes.length
end
end