Reputation: 42602
I am developing a Rails v2.3.2 app.
I have a Model with validations:
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
NOTE: The above model has attributes: name
, email
and password
(not pwd
), where password
is not directly get and store to database, instead, the user input pwd
value will be encrypted and then store as password
in database. In database table, the column(attribute) is password
. I use def pwd=(pwd) ...
to achieve this.
My Controller:
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
The view (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 %>
The interesting & strange thing is , if in the view form, I input values to every field then submit the form, my new instance created successfully.
BUT, if I leave name
and email
empty, only input password
field (which will be pwd
value) in the form, then the application got broken, with the error message:
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>
I also tried from Rails console, I can create and save object like:
Person.new(:name=>'John', :email=>'[email protected]', :pwd=>'test')
So:
1. Why I can successfully create a model instance if all fields have been filled with values in the form, BUT I got that error when I leave name
and email
empty but input value to password(pwd) field?
2. Why I do not get error message which complains the name
and email
should not be empty?
Upvotes: 0
Views: 115
Reputation: 623
To answer your second question, you're not getting the validation errors because you are not checking for them in your view. When validation fails, the error messages are added to an errors hash associated with the object you were trying to save. To optionally display them, add something similar to this to your view:
<% 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...
Upvotes: 0
Reputation: 47933
The reason is your model is missing an attribute reader (getter) for pwd
.
Here's what's happening:
As name
and email
are required (courtesy of validates_presence_of :name, :email
), when you do not enter them and submit the form, an error occurs and the form is rendered again and the view wants to fill the pwd
field, but as you haven't defined it, you get that error message: undefined method 'pwd' for #<Person:0xa0ec0e0>
.
So you can add a getter like this to your Person
class:
def pwd
"" # or whatever you like
end
And your form should work again. If you want your model to remember the unencrypted password when an error occurs, you can have something like this instead:
def pwd=(pwd)
@pwd = pwd
encrypted_pwd = pwd + randn(127)
self.password = encrypted_pwd
end
def pwd
@pwd || ""
end
Upvotes: 2