Ruby on rails 在创建之前验证关联的对象是否存在

Ruby on rails 在创建之前验证关联的对象是否存在,ruby-on-rails,validation,Ruby On Rails,Validation,我一直在学习入门rails教程,现在正在尝试一些自定义功能 我有两种型号,Person和Hangout。一个人可以有许多闲逛场所。在创建Hangout时,必须选择Person并将其与新的Hangout关联。然而,当我调用我的create操作时,我遇到了一些问题。这将在人员的验证存在之前触发 我走错方向了吗?似乎我不应该在创建验证之前创建自定义的,以确保使用人员创建了Hangout #hangout_controller def create @person = Person.find(par

我一直在学习
入门
rails教程,现在正在尝试一些自定义功能

我有两种型号,
Person
Hangout
。一个
可以有许多
闲逛场所
。在创建
Hangout
时,必须选择
Person
并将其与新的
Hangout
关联。然而,当我调用我的
create
操作时,我遇到了一些问题。这将在人员的
验证存在之前触发

我走错方向了吗?似乎我不应该在创建
验证之前创建自定义的
,以确保使用
人员
创建了
Hangout

#hangout_controller
def create
  @person = Person.find(params[:hangout][:person_id])

  @hangout = @person.hangouts.create(hangout_params)
  @hangout.save

  redirect_to hangouts_path(@hangout)
end

#hangout.rb
class Hangout < ActiveRecord::Base
  belongs_to :person

  validates_presence_of :person 
end

#person.rb
class Person < ActiveRecord::Base
  has_many :hangouts

  validates :first_name, presence: true
  validates :met_location, presence: true
  validates :last_contacted, presence: true

  def full_name
    "#{first_name} #{last_name}"
   end
end
#挂断#控制器
def创建
@person=person.find(参数[:hangout][:person\u id])
@hangout=@person.hangouts.create(hangout\u参数)
@出去玩,救命
重定向到hangout路径(@hangout)
结束
#hangout.rb
类挂起
您对控制器和模型责任感到困惑

让我试着解释一下我认为让你困惑的是什么:

首先,在您的电脑中尝试以下操作:

它不应该允许您这样做,因为您没有将
Person
对象传递给
create
方法。因此,我们确认验证工作正常。该验证意味着在创建
Hangout
之前,确保存在
person
属性。所有这些都是模型级的,还没有关于控制器的内容

让我们转到控制器部分。当控制器的创建操作“被激发”时,该控制器根本不知道您要做什么。它不运行任何验证。这只是一个操作,如果您愿意,可以调用
Hangout
模型来创建其中一个

我相信当你说“it fires”时,你是说
HangoutController
create
操作首先被调用,而不是
Hangout
模型上的
create
方法。这是完全好的。验证在模型级别运行

在验证人员的存在之前创建操作激发

我认为您对rails MVC感到困惑。表单包含url,当您提交表单时,表单参数将根据您在routes中定义的路由发送到控制器操作。rb控制器操作,在本例中为创建操作,与模型交互这是非常重要的,它会检查您的验证,如果所有验证都通过,您的对象将保存在数据库中因此,即使在您的应用程序中,控件首先传递给控制器,但如果所有验证都通过,您的对象只保存一次


现在让我们回到您的代码。有几件事你做错了

a您不需要单独关联您的联系人:

在创建操作中,有以下行:

@person = Person.find(params[:hangout][:person_id])
您不需要这样做,因为您的person_id已经来自您的表单,它会自动将您的闲逛与person关联

b您正在调用create方法而不是build:

当您调用方法时,它会为您做两件事:首先初始化您的对象,在您的情况下是您的挂起,如果所有验证都通过,它会保存它。如果没有通过所有验证,只需回滚查询即可

如果您要使用它,它只会使用表单中的参数初始化对象

c验证错误不会显示:

如上所述,由于您调用的是create方法而不是build,因此不会显示验证错误


修复

您的创建方法应如下所示:

def create
  @hangout = Hangout.new(hangout_params) # since your person_id is coming from form it'll automatically associate your new hangout with person
  if @hangout.save
    redirect_to hangouts_path(@hangout)
  else
    render "new"  # this will show up validation errors in your form if your hangout is not saved in database
  end
end

private

  def hangout_params
    params.require(:hangout).permit(:person_id, :other_attributes)
  end

嵌套属性

我认为您可以更好地使用-我们已经通过对嵌套模型使用验证实现了您之前所寻求的功能(尽管您可以使用reject_if::all_blank来避免):

虽然我没有测试过以上内容,但我相信这是您应该处理它的方式。这将基本上为特定的
人员保存
挂起
关联对象-如果
挂起
关联对象为空,则允许您拒绝

意见如下:

#app/views/hangouts/new.html.erb
<%= form_for [@person, @hangout] do |f| %>
    <%= f.fields_for :hangouts do |h| %>
       <%= h.text_field :name %>
    <% end %>

    <%= f.submit %>
<% end %>
#app/views/hangouts/new.html.erb
您会说:“但是,当我调用我的创建操作时,我遇到了问题。这会在验证for person的存在之前触发。”。什么火?
#app/models/person.rb
Class Person < ActiveRecord::Base
   has_many :hangouts
   accepts_nested_attributes_for :hangouts, reject_if: :all_blank
end

#app/models/hangout.rb
Class Hangout < ActiveRecord::Base
   belongs_to :person
end
#config/routes.rb
resources :people do
   resources :hangouts # -> domain.com/people/:people_id/hangouts/new
end

#app/controllers/hangouts_controller.rb
Class HangoutsController < ApplicationController
   def new
      @person = Person.find params[:people_id]
      @hangout = @person.hangouts.build
   end

   def create
      @person = Person.find params[:people_id]
      @person.update(hangout_attributes)
   end

   private

   def hangout_attributes
       params.require(:person).permit(hangouts_attributes: [:hangout, :attributes])
   end
end
#app/views/hangouts/new.html.erb
<%= form_for [@person, @hangout] do |f| %>
    <%= f.fields_for :hangouts do |h| %>
       <%= h.text_field :name %>
    <% end %>

    <%= f.submit %>
<% end %>