Rails:验证关联字段

时间:2014-08-31 11:52:54

标签: ruby-on-rails ruby-on-rails-3 validation simple-form

这是事情。让我们说我有一个用户模型,订单模型和地址模型。

class User < ActiveRecord::Base
     belongs_to :address, :foreign_key => :address_id, :class_name => "Address"
end

class Order < ActiveRecord::Base
     belongs_to :address, :foreign_key => :address_id, :class_name => "Address"
end

class Address < ActiveRecord::Base
   attr_accessible :email, :address
end

现在,在用户模型上,我想验证地址模型的电子邮件字段。

但是在Order模型上,我想验证地址模型的地址字段。

我试过这个:

class User < ActiveRecord::Base
     belongs_to :address, :foreign_key => :address_id, :class_name => "Address"
     validate :address_fields

     def address_fields
        self.address.errors.add 'email' unless self.address.email.present?
     end
end

它在控制台中可以正常工作,但是Simple Form没有看到错误,也没有显示错误。

有任何想法正确地做到了吗?

2 个答案:

答案 0 :(得分:1)

听起来你很亲密,但有一些细微之处取决于你想要做什么。

通常,Rails设置为以模型为中心的验证 - 也就是说,模型有效或不有效。 Rails希望您的验证出现在您正在验证的模型上,并提供validates_associated validator来帮助您。这是一个示例,我在Address上添加了一些规则,并告诉UserOrder模型在保存时验证它们。

class User < ActiveRecord::Base
  belongs_to :address
  validates_associated :address
end

class Order < ActiveRecord::Base
  belongs_to :address
  validates_associated :address
end

class Address < ActiveRecord::Base
  has_many :users
  has_many :orders
  attr_accessible :email, :address

  # This isn't a good regex for validating email addresses, it's just an example
  validates :email, format: { with: /^[A-z0-9]+@[A-z0-9.]+.[A-z]$/ }
  validates :address, presence: true
end

您还可以使用验证时的:if:unless选项conditional validations。例如,如果您想要Address上的电话号码,只要它是美国Address,您可以使用此号码:

validates :phone_number, presence: true, if: :us_address?
def us_address?
  country == "United States"
end

如果您的Address可以拥有多个用户(例如,多个人可能订购公司地址)并且可以拥有多个订单(因为客户可以订购多次),则很难编写条件验证符合您要求的规则的Address模型。我想到了几种选择:

  • 将电子邮件存储在User模型上。你不能给建筑物发电子邮件,所以它更有意义。如果您想要快照用户的电子邮件地址以便重现发票,那么可能会在confirmation_sent_to_email上添加Order字段。
  • 有两个单独的模型,OrderAddressUserAddress。它们可以具有不同的验证规则,并且在您的应用程序中将更清楚您正在处理的类型。您仍然可以拥有仅包含地址详细信息的Address模型,并根据需要将其与OrderAddressUserAddress模型相关联。

答案 1 :(得分:1)

一个简单的答案。

向用户添加错误而不是user.address。

class User < ActiveRecord::Base
     def address_fields
        self.errors.add 'email' unless self.address.email.present?
     end
end

然后,您可以在简单用户表单上看到错误。

或者您可以像这样更新用户表单,以处理user.errors和user.address.errors:

  <% if @user.errors.any? || @user.address.errors.any?%>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count + @user.address.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
      <ul>
      <% @user.address.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>