gpt4 book ai didi

ruby-on-rails - Ruby on Rails : How to validate nested attributes on certain condition?

转载 作者:数据小太阳 更新时间:2023-10-29 06:47:46 26 4
gpt4 key购买 nike

我有这些模型:

class Organisation < ActiveRecord::Base

has_many :people
has_one :address, :as => :addressable,
:dependent => :destroy
accepts_nested_attributes_for :address, :allow_destroy => true

end

class Person < ActiveRecord::Base

attr_accessible :first_name, :last_name, :email, :organisation_id, :address_attributes

belongs_to :user
belongs_to :organisation
has_one :address, :as => :addressable,
:dependent => :destroy
accepts_nested_attributes_for :address, :allow_destroy => true

# These two methods seem to have no effect at all!
validates_presence_of :organisation, :unless => "address.present?"
validates_associated :address, :unless => "organisation.present?"

end

class Address < ActiveRecord::Base

belongs_to :addressable, :polymorphic => true

validates_presence_of :line1, :line2, :city, :zip

end

...以及这些观点:

_fields.html.erb :
<%= render 'shared/error_messages', :object => f.object %>
<fieldset>
<div class="left">
<%= f.label :first_name %><br/>
<%= f.text_field :first_name %>
</div>
<div>
<%= f.label :last_name %><br/>
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :email %><br/>
<%= f.text_field :email %>
</div>
<div>
<%= f.label :organisation_id %><br/>
<%= f.select(:organisation_id, current_user.organisation_names, {:include_blank => "--- None ---"}, :id => 'organisation_select') %>
</div>
</fieldset>

<%= f.fields_for :address do |address| %>
<%= render 'shared/address', :f => address %>
<% end %>

_address.html.erb:
<fieldset id="address_fields">
<div>
<%= f.label :line1 %>
<%= f.text_field :line1 %>
</div>
<div>
<%= f.label :line2 %>
<%= f.text_field :line2 %>
</div>
<div>
<%= f.label :zip %>
<%= f.text_field :zip %>
</div>
<div>
<%= f.label :city %>
<%= f.text_field :city %>
</div>
</fieldset>

people_controller.rb :
def new
puts params.inspect
@person = Person.new(:organisation_id => params[:organisation_id])
@person.build_address
@title = "New person"
end

{"action"=>"new", "controller"=>"people"}

def edit
puts params.inspect
@title = @person.name
end

{"action"=>"edit", "id"=>"69", "controller"=>"people"}

def create
puts params.inspect
if params[:organisation_id]
@person = current_user.organisations.build_person(params[:person])
else
@person = current_user.people.build(params[:person])
end
if @person.save
flash[:success] = "Person created."
redirect_to people_path
else
render :action => "new"
end
end

{"commit"=>"Create", "action"=>"create", "person"=>{"last_name"=>"Doe", "organisation_id"=>"9", "email"=>"john.doe@email.com", "first_name"=>"John", "address_attributes"=>{"city"=>"Chicago", "zip"=>"12345", "line2"=>"Apt 1", "line1"=>"1 Main Street"}}, "authenticity_token"=>"Jp3XVLbA3X1SOigPezYFfEol0FGjcMHRTy6jQeM1OuI=", "controller"=>"people", "utf8"=>"✓"}

在我的 Person 里面模型我需要确保只有当一个人的 organisation_id为空,该人的地址字段必须存在。

我试过这样的事情:
validates :address, :presence => true, :if => "organisation_id.blank?"

但它不起作用。

如何才能做到这一点?

谢谢你的帮助。

最佳答案

首先,我想确定你的意思是blank?而不是 present? .通常,我看到这个:

validate :address, :presence_of => true, :if => 'organisation.present?'

意思是,如果组织也存在,您只想验证地址。

关于, :accepts_nested_attributes_for ,您是通过传入嵌套的表单属性来使用此功能,还是诸如此类?我只是想确保您绝对需要使用此功能。如果您实际上没有处理嵌套的表单属性,则可以使用以下方法实现级联验证:
validates_associated :address

如果您确实需要使用 :accepts_nested_attributes ,请务必查看 :reject_if范围。基本上,如果某些条件适用,您可以完全拒绝添加属性(及其后代):
accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => :no_organisation

def no_organisation(attributes)
attributes[:organisation_id].blank?
end

现在,如果以上都不适用,让我们来看看你的语法:

它应该可以工作, :if/:unlesssymbols, strings and procs .您不需要指向foreign_key,但可以通过指向来简化:
:if => "organisation.blank?"

您在 Address 模型中有其他验证,对吗?当您不希望地址被验证时,它会被验证吗?或者地址没有被验证?如果你能给我一些额外的细节,我可以帮你在控制台中测试它。

  • 为了让我自己更轻松:批量分配,我更改了 rails 配置:config.active_record.whitelist_attributes = false
  • 我创建了 a gist for you to follow along
  • 我也有一个示例项目。如果您有兴趣,请告诉我。

    基本点:
  • 将以下内容添加到 Person 以确保 Org 或 Address 有效:
    validates_presence_of :organisation, :unless => "address.present?"validates_associated :address, :unless => "organisation.present?"
  • 添加了对 Address 的验证以在 Org 不存在时触发错误:validates_presence_of :line1, :line2, :city, :zip
    我能够产生您正在寻求的要求。请看 at the gist I created我有一个完整的控制台测试计划。


  • 我加了 a controller file to the previous gist .

    概述:
  • 创建此人所需的全部内容是:@person = current_user.people.build(params[:person])
  • :organisation_id 将始终从 :person 参数节点中找到,如下所示:params[:person][:organisation_id]所以你如果永远不会是真的。


  • 我更新了要点,对 the controller 进行了必要的更改, the modelthe form .

    概述:
  • 您需要清理 Controller 。您正在使用 accepts_nested_attribute ,所以在 :create 中,你只关心 params[:person] .此外,在 render :new ,您需要设置部分将使用的任何实例变量。这是不是 回去通过:new行动。 :new:edit行动也需要简化。
  • 您的 Person 模型需要使用 :reject_if参数,因为地址字段返回到 :create 操作为 :address_attributes => {:line1 => '', :line2 => '', etc} .如果有任何值,您只想创建关联。那么你的 validates_presence_of:organisation会工作得很好。
  • 您的表单需要将组织 ID 传递给 Controller ​​,而不是组织名称

    尽在the gist


  • 应该是 the final gist .

    概述:
  • 在构建@person 后立即将以下内容添加到您的编辑操作中:

    @person.build_address 如果@person.address.nil?
    这确保您有地址输入,即使 @person.address 不存在。它不存在,因为 accepts_nested_attributes 上的 :reject_if 条件
  • 我干了 :reject_if 如下。它有点hacky,但有一些实用性:
    accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => :attributes_blank?

    def attributes_blank?(attrs)
    attrs.except('id').values.all?(&:blank?)
    end

    一种。 attrs -> params[:person][:address] 的结果
    .except('id') -> 返回除 'id' 之外的所有键值
    C。 .values -> 将散列中的所有值作为数组返回
    d. .all? -> 数组中的所有元素是否满足以下检查
    e. &:blank -> 块的 ruby​​ 简写,像这样:all?{ |v| v.blank? }
  • 关于ruby-on-rails - Ruby on Rails : How to validate nested attributes on certain condition?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12770018/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com