Rails开放时间验证

时间:2019-01-14 14:21:20

标签: ruby-on-rails cocoon-gem

我有一个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]]

2 个答案:

答案 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