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. http://railscasts.com/episodes/219-active-model

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: