Validates_presence_of not working

Hi,

I’m new to ruby and rails. I just created a simple update page and the
update works fine if all form fields are filled in. However there is one
field that should never be allowed to be blank. So I put this in my
model:

class Topic < ActiveRecord::Base
validates_presence_of :dr_title
validates_length_of :dr_title, :minimum => 1

So, when I submit the form with a blank dr_title, I should see an error
message with the offending form item highlighted, correct? That doesn’t
happen. It just goes on to the next page as though it worked fine, but
in fact it doesn’t do the update.

I am using Topic.update() instead of Topic.save(), so I tried adding the
:on => :update parameter to the validation method calls in my model, but
that made no difference (I don’t understand that parameter anyway; I
want the validation enforced whether I am saving or updating or
creating, is there a way to specify all?)

Here is the controller method:

def updatetopic
fields = params[:topic]

     # if checkbox was unchecked, mark it false
 if fields[:inlibrary] == nil
   fields[:inlibrary] = false
 end

 Topic.update(params[:id], fields)
 msg = "Updated Topic Successfully"
 flash[:notice] = msg
 redirect_to(:action => "welcome")

end

And here is the view:
<%= start_form_tag(:action => “updatetopic”) %>
<%= hidden_field_tag “id”, @topic.id %>

dr_title: <%= text_field("topic", "dr_title", "size" => 40 ) %>
title: <%= text_field("topic", "title", "size" => 40 ) %>
inlibrary: <%= check_box_tag("topic[inlibrary]","true", @topic.inlibrary, :id => "topic_inlibrary") %>
keywords: <%= text_field("topic", "keywords", "size" => 40 ) %>
<%= submit_tag(" UPDATE ") %>
<%= end_form_tag %>

Hope someone can help. Thanks.

Typically you’d need something like the following in your view in
order to display the error messages on the page:

<%= error_messages_for ‘topic’ %>

You also may want to do something a little different in your code
depending on whether or not the update / save was successful:

 if Topic.update(params[:id], fields)
   msg = "Updated Topic Successfully"
   flash[:notice] = msg
   redirect_to(:action => welcome)
 else
   render :action => 'updatetopic'
 end

Hope this helps.

On 12/16/05, Steven S. [email protected] wrote:

Typically you’d need something like the following in your view in

Is there some way to generate javascript to check on the
client.simplechecks like null and numericality are better done at
client side…Does rails
support this or do we have to write it ourselves? It seems like a good
feature to add.

Thanks

Steven S. wrote:

Typically you’d need something like the following in your view in
order to display the error messages on the page:

<%= error_messages_for ‘topic’ %>

You also may want to do something a little different in your code
depending on whether or not the update / save was successful:

 if Topic.update(params[:id], fields)
   msg = "Updated Topic Successfully"
   flash[:notice] = msg
   redirect_to(:action => welcome)
 else
   render :action => 'updatetopic'
 end

Hope this helps.

Thanks, you’ve helped me out some, but not completely. Now I have the
right line in my view to display error messages, and I know how to
re-render the form view.

However, the problem is that the update() method does not return true or
false. See this from the ActiveRecord.update() documentation
(http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M000719):

"update(id, attributes)

Finds the record from the passed id, instantly saves it with the passed
attributes (if the validation permits it), and returns it. If the save
fails under validations, the unsaved object is still returned."

I’m not sure what this means. And there is no way to tell from the
returned object whether the update was successful. So, I’m back at
square one. Failed updates take me to the welcome action, just like
successful ones. I vaguely remember reading something about the solution
to this, but danged if I can remember.

Also, I have a page to create a new action. It doesn’t have a controller
method because I don’t need to prepopulate anything in the page. What
line should I put in the view to display errors?

Thanks very much,
D

Steven S. wrote:

Typically you’d need something like the following in your view in
order to display the error messages on the page:

<%= error_messages_for ‘topic’ %>

You also may want to do something a little different in your code
depending on whether or not the update / save was successful:

 if Topic.update(params[:id], fields)
   msg = "Updated Topic Successfully"
   flash[:notice] = msg
   redirect_to(:action => welcome)
 else
   render :action => 'updatetopic'
 end

Hope this helps.

Hello,

Seems that update always returns the record with an added field
“errors”. So
you can test:

  if Topic.update(params[:id], fields).errors.count == 0
    msg = "Updated Topic Successfully"
    flash[:notice] = msg
    redirect_to(:action => welcome)
  else
    render :action => 'updatetopic'
  end

Francois

I’m not sure what this means. And there is no way to tell from the
returned object whether the update was successful. So, I’m back at
square one. Failed updates take me to the welcome action, just like
successful ones. I vaguely remember reading something about the solution
to this, but danged if I can remember.

You can try:
object = find(id)
if object && object.update_attributes(attributes)

Francois GORET wrote:

Hello,

Seems that update always returns the record with an added field
“errors”. So
you can test:

  if Topic.update(params[:id], fields).errors.count == 0
    msg = "Updated Topic Successfully"
    flash[:notice] = msg
    redirect_to(:action => welcome)
  else
    render :action => 'updatetopic'
  end

Francois

OK, thanks. I made some progress there. That is the correct test to
determine whether the udpate succeeded (I’m sure Cuong’s works too).

So now I go back to the update action if the update failed. However, I
don’t see the errors listed or the offending form fields highlighted.

Actually, I’m working with the create new topic controller/form now, not
the update one, because it’s a little cleaner. I’m trying to base it as
closely as possible on the new product controller/form from the depot
demo application in the Rails book, which may have been generated using
scaffold. That demo app works fine, if you leave the form blank it
prints nicely formed errors and highlights the offending form item(s).

I have copied pretty much exactly what they are doing, only changing
model class names, etc. I have the stylesheet and all other necessary
files that I know of.

The problem is that when I try and create a new topic with a blank
dr_title field, it does indeed take me back to the form, but I get this
error:
NoMethodError in Topic#createnewtopic

Showing app/views/topic/_form.rhtml where line #1 raised:

You have a nil object when you didn’t expect it!
You might have expected an instance of ActiveRecord::Base.
The error occured while evaluating nil.errors

Extracted source (around line #1):

1: <%= error_messages_for ‘topic’ %>
2:
3:


4:

It doesn’t like line 1. But my controller method explictly populates
@topic.
The same code works fine in the demo app.

Here are relevant bits of code:

controller methods:

def newtopic
@topic = Topic::new
end

def createnewtopic
fields = params[:topic]

 if fields[:inlibrary] == nil
   fields[:inlibrary] = false
 end

 topic = Topic.new(fields)
 if topic.save
	 flash[:notice] = "Topic updated successfully"
     redirect_to(:action => "index")
 else
 	render :action => 'newtopic'
 end

end

view:

<%= start_form_tag(:action => “createnewtopic”) %>
<%= render :partial => ‘form’ %>
<%= submit_tag “Create” %>
<%= end_form_tag %>

form partial:

<%= error_messages_for ‘topic’ %>

dr_title: <%= text_field("topic", "dr_title", "size" => 40 ) %>
title: <%= text_field("topic", "title", "size" => 40 ) %>
inlibrary: <%= check_box_tag("topic[inlibrary]","true", true, :id => "topic_inlibrary") %>
keywords: <%= text_field("topic", "keywords", "size" => 40 ) %>

Why does rails choke on the first line of that partial?
D

hmm do you create on instance variable @topic in your createnewtopic
action?
i didn’t see one (@topic = Topic.new(params[:topic]))

this is needed since most of the form tags (text_field, password) and
error_messages_for require that a relevant model instance variable be
present.

When you say

“error_messages_for(‘topic’)”

error_messages_for will look for a @topic variable, if no variable is
found
it will throw an error.

Steven S. wrote:

Regarding displaying the errors, etc. on the update view, do you have
a scaffold.css in public>stylesheets? If so, does it contain
‘fieldWithErrors’, and the various ‘ErrorExplanation’ entries?

Yes.

Regarding displaying the errors, etc. on the update view, do you have
a scaffold.css in public>stylesheets? If so, does it contain
‘fieldWithErrors’, and the various ‘ErrorExplanation’ entries?

Based on my recollection of the earlier code you posted, the only
difference between what you’ve coded in the updatetopic method and
similar code I have working is that you’re using a Class method of
Topic to update a topic (i.e., Topic.update) and I’m using an
instance method (@topic.save) to update a specific topic as below:

@topic = Topic.new(params[:topic])

 if @topic.save
   flash[:notice] = 'Updated Topic successfully.'
   redirect_to :action => 'welcome'
 else
   render :action => 'update_topic'
 end

I don’t know if will help or not but it’s the only difference I can
think of at the moment.

Steven S. wrote:

Based on my recollection of the earlier code you posted, the only
difference between what you’ve coded in the updatetopic method and
similar code I have working is that you’re using a Class method of
Topic to update a topic (i.e., Topic.update) and I’m using an
instance method (@topic.save) to update a specific topic as below:

@topic = Topic.new(params[:topic])

 if @topic.save
   flash[:notice] = 'Updated Topic successfully.'
   redirect_to :action => 'welcome'
 else
   render :action => 'update_topic'
 end

I don’t know if will help or not but it’s the only difference I can
think of at the moment.

Hi Steven. Thanks very much for your help. There are two cases I am
trying to get working–the create new topic case, which uses the
instance method topic.save(), and the update topic case, which uses the
class method Topic.update. I have the same problem with both. Now I can
at least detect the error in both cases and the webapp redirects
appropriately, but it doesn’t display the error info in the view because
it doesn’t like this line:
<%= error_messages_for ‘topic’ %>. Also, the form elements are not
highlighted, even though the stylesheet stuff is in place and the layout
is using it.

ANyway, thanks again.

On 17-dec-2005, at 1:57, Dan T. wrote:

   flash[:notice] = 'Updated Topic successfully.'

instance method topic.save(), and the update topic case, which uses
is using it.
The thing is, ‘topic’ mades the assumptioon that you will have an
instance variable called @topic. When you use Topic.update(id,
new_attributes) it doesn,t get saved.

If you REALLY want to keep using the class method instead of
update_attributes, you can ask the topic returned from the “update”
method for validity, like so:

@topic = Topic.update(id, new_topic_attributes) # receive the

topic into the instance var

redirect_to :action=>'thanks_for_editing' and return if

@topic.valid? # the key


Julian ‘Julik’ Tarkhanov
me at julik.nl