Forum: Ruby on Rails validates_presence_of not working

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Dan (Guest)
on 2005-12-16 06:46
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 %>
<table>
	<tr>
		<td>dr_title:</td>
		<td><%= text_field("topic", "dr_title", "size" => 40 ) %></td>
	</tr>
	<tr>
		<td>title:</td>
		<td><%= text_field("topic", "title", "size" => 40 ) %></td>
	</tr>
	<tr>
		<td>inlibrary:</td>
		<td>
			<%= check_box_tag("topic[inlibrary]","true", @topic.inlibrary, :id =>
"topic_inlibrary") %>
		</td></tr>
	<tr>
	<tr>
		<td>keywords:</td>
		<td><%= text_field("topic", "keywords", "size" => 40 ) %></td>
	</tr>
	<tr>
		<td></td>
		<td><%= submit_tag(" UPDATE ") %></td>
	</tr>
</table>
<%= end_form_tag %>

Hope someone can help. Thanks.
Steven S. (Guest)
on 2005-12-16 08:39
(Received via mailing list)
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.
Vivek K. (Guest)
on 2005-12-16 09:06
(Received via mailing list)
On 12/16/05, Steven S. <removed_email_address@domain.invalid> 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
Dan (Guest)
on 2005-12-16 10:53
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/Ba...

"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.
Francois GORET (Guest)
on 2005-12-16 11:49
(Received via mailing list)
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
Cuong T. (Guest)
on 2005-12-16 13:04
(Received via mailing list)
>
> 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)
           .....
Dan (Guest)
on 2005-12-16 19:56
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: <!--[form:topic]-->
3: <table>
4: 	<tr>

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' %>
<!--[form:topic]-->
<table>
	<tr>
		<td><label for="topic_dr_title">dr_title:</label></td>
		<td>
			<%= text_field("topic", "dr_title", "size" => 40 ) %>
		</td>
	</tr>
	<tr>
		<td><label for="topic_title">title:</label></td>
		<td><%= text_field("topic", "title", "size" => 40 ) %></td>
	</tr>
	<tr>
		<td><label for="topic_inlibrary">inlibrary:</label></td>
		<td>
			<%= check_box_tag("topic[inlibrary]","true", true, :id =>
"topic_inlibrary") %>
		</td></tr>
	<tr>
	<tr>
	<td><label for="topic_keywords">keywords:</label></td>
		<td><%= text_field("topic", "keywords", "size" => 40 ) %></td>
	</tr>
</table>
<!--[eoform:topic]-->

Why does rails choke on the first line of that partial?
D
Cyril Ucron D. (Guest)
on 2005-12-16 20:07
(Received via mailing list)
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. (Guest)
on 2005-12-16 20:07
(Received via mailing list)
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?
Dan (Guest)
on 2005-12-17 00:34
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.
Steven S. (Guest)
on 2005-12-17 01:55
(Received via mailing list)
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.
Dan T. (Guest)
on 2005-12-17 02:57
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.
Julian 'Julik' Tarkhanov (Guest)
on 2005-12-17 18:00
(Received via mailing list)
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
This topic is locked and can not be replied to.