我一直在关注Getting Started
rails教程,现在正在尝试一些自定义功能。
我有2个模型,Person
和Hangout
。 Person
可以包含多个Hangouts
。创建Hangout
时,必须选择Person
并与新Hangout
相关联。但是,当我调用create
动作时,我遇到了问题。这会在validate_presence_of
之前触发。
我是以错误的方式来做这件事的吗?似乎我不应该创建自定义before_create
验证,以确保使用Hangout
创建Person
。
#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
答案 0 :(得分:2)
在人员的validate_presence_of之前触发创建操作
我认为你对rails MVC感到困惑。 您的表单包含一个网址,当您提交表单时,您的表单参数将根据您在routes.rb中定义的路由发送到您的控制器操作您的控制器操作,在这种情况下创建操作,与模型交互,这是检查您的验证,如果所有验证都通过,您的对象将保存在数据库中,所以即使在您的应用程序中控件首先传递给您的控制器,但您的对象是如果所有验证都通过,则只保存一次。
现在让我们回到你的代码。有几件事你做错了
一个。 您无需单独关联您的人员
在你的创作中你有这一行:
@person = Person.find(params[:hangout][:person_id])
您不需要这样做,因为您的person_id已经来自您的表单,它会自动将您的视频群聊与此人关联。
湾您正在调用create方法而不是build:
当你调用.association.create
方法时,它会为你做两件事,它首先初始化你的对象,在你的情况下是你的环聊,如果所有的验证都被传递,它会保存它。如果未传递所有验证,则只需回滚查询。
如果您使用.association.build
,它只会使用来自您表单的参数初始化您的对象
℃。 验证错误不会显示:
如上所述,由于您正在调用create方法而不是构建,因此您的验证错误将不会显示。
<强>修正强>
您的create方法应如下所示:
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
答案 1 :(得分:0)
您对控制器和模型职责感到困惑。
让我试着解释一下我认为令你困惑的事情:
首先在rails console:
中尝试此操作Hangout.create
它不应该让你,因为你没有将Person
对象传递给create
方法。因此,我们确认验证工作正常。该验证意味着在创建Hangout
之前,请确保存在person
属性。所有这些都是在模型级别,对控制器一无所知!
让我们去控制器部分。当控制器的创建动作被触发时,该控制器根本不知道你要做什么。它没有运行任何验证。这只是一个动作,如果你愿意,可以调用Hangout
模型来创建其中一个。
我相信当你说“它发射”时您是说create
的{{1}}操作首先调用HangoutController
create
模式上的Hangout
方法。这完全没问题。验证在模型级别运行。
答案 2 :(得分:0)
嵌套属性
我认为您最好使用accepts_nested_attributes_for
- 我们已经通过在嵌套模型上使用验证来实现您之前寻求的功能(尽管您已经能够使用reject_if :: all_blank):
#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
这将使您能够调用reject_if: :all_blank
方法 -
传递:all_blank而不是Proc将创建一个proc 拒绝所有属性为空的记录,不包括任何值 为_destroy。
-
这意味着您可以创建以下内容:
#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
虽然我没有测试过上述内容,但我相信这是你应该处理的方式。这基本上会保存特定Hangout
的{{1}}关联对象 - 允许您拒绝Person
关联对象为空
观点如下:
Hangout