当验证失败时,Rails如何保留表单数据?

时间:2016-11-28 15:28:51

标签: ruby-on-rails

我有一个'创造' Rails中的action方法和:

def create
  @movie = Movie.new(movie_params)
  if @movie.save
    redirect_to @movie, notice: "Movie successfully created"
  else
    render :new
  end
end

现在,我对Movie模型进行了一些验证。如果这些验证失败,@movie.save返回false,我只需调用new模板(不触及new操作,因为render :newrender template: 'new'相同}。

我不明白当Rails再次呈现new视图时,Rails如何保留我已输入的表单数据。在幕后发生了什么让它能够做到这一点?

4 个答案:

答案 0 :(得分:13)

让我们尝试逐点理解整个过程

控制器操作中定义的实例变量与渲染视图共享。

在你的情况下,我假设有new动作类似

def new
  @movie = Movie.new
end

你有一个相应的视图new.html.erb,你已经创建了一个像这样的表单

= form_for @movie do |f|

现在,您知道@movie方法中传递的form_for对象已在new操作中定义。大多数情况下,我们都没有将任何参数传递给new操作中的new方法。加载表单时表单字段为空白,因为对象的属性(在您的情况下为@movie)默认为空,因为我们只是初始化一个空对象(Movie.new)。

我们假设您的Movie模型具有name属性,请尝试在new操作中执行此操作

def new
  @movie = Movie.new(name: 'Hello World!')
end

现在,当您要加载新操作时,您会在Hello World!文本字段中看到name,因为您的@movie对象已使用此值进行初始化。

另外,请记住,在这种情况下,Rails Convention-Over-Configuration会自动生成表单URL,默认情况下它指向create操作。当您提交form时,会对创建操作发出请求。这让我想到了下一点。

当我们提交表单时,所有填写的表单值都会发送到路径与表单网址匹配的操作(在您的情况下网址指向create操作)

create操作中,您将以散列形式接收参数,其中模型属性(Movie属性)作为键,填充信息作为其值。 create操作的第一行是

@movie = Movie.new(movie_params)

这是一行非常重要的代码,试着理解这一点。假设您的表单只有一个文本字段,即name。现在movie_params是一个看起来像这样的方法

def movie_params
  params.require(:movie).permit(:name)
end

现在,movie_params方法将返回类似{ 'name' => 'Hello World!' }的哈希,现在您将此哈希作为参数传递给Movie.new方法。

现在,在分解代码后,您的创建操作的第一行看起来像

@movie = Movie.new({ name: 'Hello World!' })

这意味着您的@movie实例变量包含Movie类的对象,name属性设置为Hello World!。在此处,初始化后,如果您执行@movie.name,则会返回Hello World!

现在,在第二行中,您正在调用@movie.save,因为您在问题中已经提到的验证失败而返回false。当它返回false时,执行将转到else部分。现在这将我带到下一点。

在控制器中调用render :action(在您的情况下为render :new)仅呈现属于该操作但不执行该操作代码的视图。

在您的情况下,您调用了render :new,因此您实际上在创建操作中呈现new.html.erb视图。换句话说,您只是使用new.html.erb中的代码而不是new操作中的代码。在这里,render :new实际上不会调用新操作,它仍然在创建操作中,但呈现new.html.erb视图。

现在,在new.html.erb中,您创建了一个类似于

的表单
= form_for @movie do |f|

正如我在第一点所解释的那样,在操作中声明的实例变量由呈现的视图共享,在这种情况下,您在@movie操作中定义的create对象是共享的通过创建操作中呈现的new.html.erb。在我们的示例中,在create操作中,@movie对象已使用参数(movie_params)中收到的一些值进行初始化,现在new.html.erb在{else中呈现1}},默认情况下在表单中使用相同的@movie对象。你说得对,你在这里看到了魔力吗?

这就是Rails的工作方式,这就是为什么我们遵循惯例时它真棒! :)

这些博客将帮助您更好地理解代码,

http://blog.markusproject.org/?p=3313

这个要点很棒,

https://gist.github.com/jcasimir/1210155

最后但并非最不重要的是,关于布局和渲染的官方Rails指南

http://guides.rubyonrails.org/v4.2/layouts_and_rendering.html

希望以上示例清除您的疑虑,如果没有,请随时在下面的评论框中删除您的查询。 :)

答案 1 :(得分:1)

form_for助手从@movie变量中获取数据。在create操作表单中,数据会分配给@movie变量。当您致电render :new时,form_for会从@movie变量中获取列数据。

答案 2 :(得分:1)

我不确定你想要去多深,但基本上当你对create方法发布POST时,数据会传递到paramsparams只是一个key:值对,其中键和值是字符串,但rails具有特殊的语法和方法,可用于转换为哈希值。 params数据传递Movie数据以进行处理,结果存储在@movie中。呈现表单时,@movie日期将传递回表单 - 该数据用于重新填充表单。

我建议您使用blog postthe rails guide进一步阅读。

答案 3 :(得分:0)

提交表单时。您可以调用create方法,其中movie_params的所有值都在@movie中初始化。现在由于任何原因代码中断,您为相同的对象(render new)调用@movie。因此形式提出了价值观。

在整个过程中意味着您的@movie对象仍然存在。