提交一个简单的表单来创建新的模型实例时非常有趣

时间:2011-12-16 12:47:06

标签: ruby-on-rails

我正在开发 Rails v2.3.2 应用。

我有一个带有验证的模型

class Person < ActiveRecord::Base 
  validates_presence_of :name, :email

  # Please notice this method
  def pwd=(pwd)
      encrypted_pwd = pwd + randn(127)
      self.password = encrypted_pwd  
  end
end 

注意:以上模型具有以下属性:nameemailpassword(不是pwd),其中password不直接获取并存储到数据库,而是将用户输入pwd值加密,然后将其存储为password在数据库中。在数据库表中,列(属性)为password。我使用def pwd=(pwd) ...来实现这一目标。

我的控制器

class PersonsController < ApplicationController
   def create
     @person = Person.new(params[:person])
     if @person.save
       redirect_to persons_path
     else
       render :action=> :new
     end
   end

   def new
     #empty
   end

   def index
     @persons = Person.all
   end
end

视图views/persons/new.html.erb):

 <% form_for :person, @person, :url => persons_url, :html=>{:method=>:post} do |f| %>
    <table>
      <tr>
        <td>Name:</td>
        <td><%= f.text_field :name %></td>
      </tr>
      <tr>
        <td>Email:</td>
        <td><%= f.text_field :email %></td>
      </tr>
      <tr>
        <td>password:</td>
        <td><%= f.text_field :pwd %></td> <!--NOTE: here I use :pwd not :password-->
      </tr>
    </table>
    <%= f.submit "Save"%>
<% end %>

有趣&amp;奇怪的是,如果在视图表单中,我将值输入到每个字段然后提交表单,我的新实例已成功创建

但是,如果我离开nameemail 为空输入password字段(表单中的pwd值),然后应用程序被破坏,并显示错误消息:

ActionView::TemplateError (undefined method `pwd' for #<Person:0xa0ec0e0>) on line #25 of app/views/persons/new.html.erb:
22:       </tr>
23:       <tr>
24:         <td>password:</td>
25:         <td><%= f.text_field :pwd %></td>
26:       </tr>
27:     </table>

我也试过 Rails控制台,我可以创建和保存对象:

Person.new(:name=>'John', :email=>'john@gmail.com', :pwd=>'test')

所以:

1。为什么我可以成功创建模型实例,如果所有字段都填写了表单中的值,但我得到了错误,当我离开nameemail时空但输入密码(密码)字段的值?

2。为什么我没有收到抱怨nameemail不应为空的错误消息?

2 个答案:

答案 0 :(得分:2)

原因是您的模型缺少pwd的属性读取器(getter)。

以下是发生的事情:

由于nameemail是必需的(由validates_presence_of :name, :email提供),当您不输入并提交表单时,会发生错误并再次呈现表单和视图想要填充pwd字段,但由于您尚未定义,因此会收到以下错误消息:undefined method 'pwd' for #<Person:0xa0ec0e0>

因此,您可以将这样的getter添加到Person类:

def pwd
  "" # or whatever you like
end

你的表格应该再次运作。如果您希望模型在发生错误时记住未加密的密码,您可以改为:

def pwd=(pwd)
  @pwd = pwd
  encrypted_pwd = pwd + randn(127)
  self.password = encrypted_pwd
end

def pwd
  @pwd || ""
end

答案 1 :(得分:0)

要回答第二个问题,您没有收到验证错误,因为您没有在视图中检查它们。验证失败时,错误消息将添加到与您尝试保存的对象关联的错误哈希中。要选择性地显示它们,请在视图中添加与此类似的内容:

<% form_for :person, @person, :url => persons_url, :html=>{:method=>:post} do |f| %>
  <% if @person.errors.any? %>
    <ul id="errors">
    <% @person.errors.full_messages.each do |error| %>
      <li>
        <%= error %>
      </li>
    <% end %>
    </ul>
  <% end %>

Rest of your form goes here...