Validations doesnt work with activemodel?

Hi,

I have a form with 2 attributes/fields. As im not storing them in a database, i have used activemodel::validations for validations in my model class.

In the views file i have 2 associated text fields (part of a form) with a submit button. I have used validates_presence_of for the 2 attributes, but i dont see an error even when i click the submit button with empty fields. How do i validate stuff in the form?

Well, there could be several things going on. So, lets go step by step.

  1. Open an irb console (if you are using rails, type “rails console”)

  2. Try to create a new model and call valid? on it. What does it return?

Play around in the console so you can learn if your model is validating as expected (better yet, write some tests). If it’s validating correctly, I would then move to your controller and see that the code there is behaving as expected. Once you do that, make sure that view is somehow displaying the errors.

If you need more help with any step, please provide relevant code, so someone can better help you.

Hi,

Thanks for the suggestions. I have now included the code to display the error messages. Here is the code for my MVC

model class Record   include ActiveModel::Validations   validates: :ipaddress, :name, :presence => true end

View

    <%= form_for :Record, :url => {:action => 'submit'} do |f| %>       <%= f.error_messages %>       <div class="field">         <%= f.label :ipaddress %><br />         <%= f.text_field :ipaddress %>       </div>       <div class="field">         <%= f.label :name %><br />         <%= f.text_field :name %>       </div>       <div class="actions">         <%= f.submit "Submit"%>       </div>     <% end %>

Controller Somehow this gets routed to action "create" instead of "submit" when the submit button is called. Not sure why it is

def create -> same for def submit too

  respond_to do |format|      if PARAM matches so and so        DEPENDING on params this gets routed to different page      else        format.html { redirect_to records_url}        format.json { head :no_content }     end   end

end

Should i write my controller differently to handle the errors?

validates**:** ← is only validates, without punctuation.

with colon you are creating a hash, not running the macro.

I'm sorry, I dont know how it ended up in the post , but my code doesnt have the extra colon.

Its actually this model class Record   include ActiveModel::Validations   validates :ipaddress, :name, :presence => true end

Hi,

Thanks for the suggestions. I have now included the code to display the error messages. Here is the code for my MVC

model class Record include ActiveModel::Validations validates: :ipaddress, :name, :presence => true end

View

   <%= form_for :Record, :url => {:action => 'submit'} do |f| %>

Leave off the {:action} part here, I'll explain why in a moment

     <%= f.error_messages %>      <div class="field">        <%= f.label :ipaddress %><br />        <%= f.text_field :ipaddress %>      </div>      <div class="field">        <%= f.label :name %><br />        <%= f.text_field :name %>      </div>      <div class="actions">        <%= f.submit "Submit"%>      </div>    <% end %>

Controller Somehow this gets routed to action "create" instead of "submit" when the submit button is called. Not sure why it is

If your routes look like

  resources :yourmodel

Then you are using REST URLs, and a POST from your form will always go to #create, and a PUT (which you will automatically get from the form_for if your resource has an id) will always go to #update. If you want to use the submit method in place of create, you can probably do that in your routes file, but why?

def create -> same for def submit too

respond_to do |format|     if PARAM matches so and so       DEPENDING on params this gets routed to different page

at any point here do you instantiate a new instance of your model, assign the params to it, and try to save it? Until you try to save, your validations won't fire.

    else       format.html { redirect_to records_url}       format.json { head :no_content }    end end

end

Should i write my controller differently to handle the errors?

You might want to look at a vanilla scaffold controller and see how it's done canonically before you reinvent the wheel. There are separate create and update methods for a reason.

Walter

Hi Walter,

Thanks for your comments.

def create -> same for def submit too

respond_to do |format|     if PARAM matches so and so       DEPENDING on params this gets routed to different page

at any point here do you instantiate a new instance of your model, assign the params to it, and try to save it? Until you try to save, your validations won't fire.

I didn't instantiate a new instance of my model. When i try to instantiate

@record = Record.new(params[:record]) fires an error "wrong number of arguments ( 1 for 0) " I have removed the default new definition, as i thought i dont need it(im not storing the info in a DB, but processing the form data)

    else       format.html { redirect_to records_url}       format.json { head :no_content }    end end

end

Should i write my controller differently to handle the errors?

You might want to look at a vanilla scaffold controller and see how it's done canonically before you reinvent the wheel. There are separate create and update methods for a reason.

Hi Walter,

Thanks for your comments.

def create -> same for def submit too

respond_to do |format|    if PARAM matches so and so      DEPENDING on params this gets routed to different page

at any point here do you instantiate a new instance of your model, assign the params to it, and try to save it? Until you try to save, your validations won't fire.

I didn't instantiate a new instance of my model. When i try to instantiate

@record = Record.new(params[:record]) fires an error "wrong number of arguments ( 1 for 0) " I have removed the default new definition, as i thought i dont need it(im not storing the info in a DB, but processing the form data)

What version of Rails? I see a Railscast here from 2010 that has that very same code, and no error. But it also has an initialize method hand-written into the model:

def initialize(attributes = {})   attributes.each do |name, value|     send("#{name}=", value)   end end

You might need something like that to "persist" the data long enough for your controller to do something with it. #219 Active Model - RailsCasts

Walter

Hi,

I'm using rails 3.2.4.

I had referred to the activemodel episode from the rail casts and yes i included the initialize and persisted methods as specified. Still i dont see errors when i click the submit button with empty values

model class Record   include ActiveModel::Validations   include ActiveModel::Conversion   extend ActiveModel::Naming   attr_accessor :ipaddress, :name   validates: :ipaddress, :name, :presence => true   def initialize(attributes = {})     attributes.each do |name, value|       send("#{name}=", value)     end   end

  def persisted?     return false   end end

View

    <%= form_for :Record do |f| %>       <%= f.error_messages %>       <div class="field">         <%= f.label :ipaddress %><br />         <%= f.text_field :ipaddress %>       </div>       <div class="field">         <%= f.label :name %><br />         <%= f.text_field :name %>       </div>       <div class="actions">         <%= f.submit "Submit"%>       </div>     <% end %>

Controller

def new   @record = Record.new end

def create   @record = Record.new(params[:record])   respond_to do |format|      if @record.valid?        DEPENDING on params this gets routed to different page      else        format.html { redirect_to records_url}        format.json { head :no_content }     end   end

end

I dont see any errors but i see a refreshed page of records_url

Hi,

I'm using rails 3.2.4.

I had referred to the activemodel episode from the rail casts and yes i included the initialize and persisted methods as specified. Still i dont see errors when i click the submit button with empty values

model class Record include ActiveModel::Validations include ActiveModel::Conversion extend ActiveModel::Naming attr_accessor :ipaddress, :name validates: :ipaddress, :name, :presence => true def initialize(attributes = {})    attributes.each do |name, value|      send("#{name}=", value)    end end

def persisted?    return false end end

View

   <%= form_for :Record do |f| %>      <%= f.error_messages %>      <div class="field">        <%= f.label :ipaddress %><br />        <%= f.text_field :ipaddress %>      </div>      <div class="field">        <%= f.label :name %><br />        <%= f.text_field :name %>      </div>      <div class="actions">        <%= f.submit "Submit"%>      </div>    <% end %>

Controller

def new @record = Record.new end

def create @record = Record.new(params[:record]) respond_to do |format|     if @record.valid?       DEPENDING on params this gets routed to different page     else       format.html { redirect_to records_url}       format.json { head :no_content }    end end

end

I dont see any errors but i see a refreshed page of records_url

Then I would try writing just one validation, and see if you can make that work. And by the way, look, that colon at the end of validates has crept back in there. Is that a paste from your model, or your previous e-mail?

Try using

validates_presence_of :ipaddress

and see what happens.

I've never tried using ActiveModel before, so I'm guessing here.

Walter

Hi Walter,

Yah the ":" came from copy pasting my earlier comment. The result is the same(no errors) with one attribute or using validates_presense_of(tried with other validate* options too). I was wondering if that problem was to do with the view? Anyother way of displaying the errors?

Try running this in console, and see if you have any errors there. And in your view, are you using some variant of this:

    <% flash.each do |name, msg| %>     <%= content_tag :div, msg, :id => "flash_#{name}" %>     <% end %>

Walter

Hi Walter,

The validate* methods works fine on the console. The function object.valid? returns false if any of the validate method fails. For that case object.valid? returns false even in the controller function, but when i redirect to the same url, it doesn't show any errors from the code

<%= f.error_messages %>

In my view im not using any sort of this code

   <% flash.each do |name, msg| %>     <%= content_tag :div, msg, :id => "flash_#{name}" %>     <% end %>

Do i need it?

Hi Walter,

The validate* methods works fine on the console. The function object.valid? returns false if any of the validate method fails. For that case object.valid? returns false even in the controller function, but when i redirect to the same url, it doesn't show any errors from the code

The errors are set in the event loop of reading the form submission and showing the results, but when you redirect, you start a new loop, and so unless you disrupt the cycle you seem to have set for yourself, you're never going to see those errors, because the errors -- and I suspect the object -- does not exist in the context of the page you redirected to.

In a normal scaffold controller, you will see this pattern:

def new   @my_model = MyModel.new(params[:my_model]) end

def create   @my_model = MyModel.new(params[:my_model])   if @my_model.save     redirect_to some_route(@my_model), :notice => 'Yay!'   else     render :action => 'new'   end end

If both sides of your test for save are redirects, then you have to set the :warn or :error flash to your errors, because they will not persist after the redirect. Especially because you're using Active Model, but particularly because you're in a #create method -- each time that runs, the model instance is created fresh from the supplied parameters, and it forgets all about the botched save.

<%= f.error_messages %>

In my view im not using any sort of this code

  <% flash.each do |name, msg| %>    <%= content_tag :div, msg, :id => "flash_#{name}" %>    <% end %>

Do i need it?

It's what I use, it may be out of date, since I am using Rails 3.0 for this app that I copied it from. I believe that some of this was streamlined in 3.2. But I am also sure that you have to use /some/ sort of code to indicate where you want your errors to appear on your application layout file.

Walter

Hi Walter,

Thanks for the detailed explanation. I am redirecting to different pages in both the cases(valid and not valid case). Now that i am rendering a new page incase of a validate failure and i see the errors. Thank you very much :slight_smile: