I have a form that i want to appear at the top of every page so i've included it in the /app/views/layouts/application.html.erb file and i get the error undefined method
model_name' for NilClass:Class` when trying to load the page.
Here's the form snippet in application.html.erb
<%= form_for @user do |f| %>
<h3>Add new contact</h3>
<%= f.text_field :first_name %><br />
<%= f.text_field :last_name %>
<%= f.text_field :email %>
<hr />
<%= f.submit "Add Contact" %>
<% end %>
Here's my /app/controllers/user_controller.rb
class UserController < ApplicationController
def index
end
def new
@user = User.new
end
end
I'm thinking that i'm hitting this error because since the form is in the application.html.erb file, i need to somehow specify the path, but then again i'm very new to rails.
Let me know if you need anything else posted.
EDIT Following Ola's suggestion, In my app/views/layouts/application.html.erb file I have something like this:
<div>
<%= yield :add_user %>
</div>
and in my app/views/users/new.html.erb file I have this
<% content_for :add_user do %>
<%= form_for @user do |f| %>
<h3>Add new contact</h3>
First Name<br />
<%= f.text_field :first_name %><br />
Last Name<br />
<%= f.text_field :last_name %><br />
Email<br />
<%= f.text_field :email %>
<hr />
<%= f.submit "Add Contact" %>
<% end %>
<% end %>
The form is not rendered because my url is http://localhost:3000/admin/index
and so it's looking for the add_user
content_for in app/views/admin/index.html.erb
If the form is included for multiple actions (pages) you need to set @user
to something or the form_for
directive will fail (it won't have anything to create a form for).
A much better approach (and the Rails default) is to have separate views for each action, each including only the elements required by that action, and loaded into your application.html.erb
layout with <%= yield %>
. So you would have a app/views/users/new.html.erb
view which has the form in it. You never very rarely need to define any load paths in Rails, they are all derived from the model, controller and action names - or from your routes.rb
. This is a core part of the convention over configuration paradigm which runs so deep in Rails.
Edit: If you do need to have a form for creating a new object on every page (often used for UserSessions for example), you can rewrite your form_for
so that it doesn't depend on an object being present:
form_for(User.new)
or if you need to force it to post to the create
method
form_for(User.new, :url => { :action => "create" })
You can read more about resource driven form_for
in the Ruby On Rails API docs.
Did you try debugging first? I ask because you say you are new to Rails. If not, here is my approach. I want to share it, because I'm surprised how many people don't (for whatever reason) debug carefully.
(I created a test app so that I could walk through your problem. First, I visited http://localhost:3000/users
.)
First, look at the stack trace.
NoMethodError in Users#index
Showing /Users/david/dev/testapp/app/views/layouts/application.html.erb where line #11 raised:
undefined method `model_name' for NilClass:Class Extracted source (around line #11):
8: </head>
9: <body>
10:
11: <%= form_for @user do |f| %>
12: <h3>Add new contact</h3>
13: <%= f.text_field :first_name %><br />
14: <%= f.text_field :last_name %>
This tells you line 11 in your code is the problem. Think -- what could be the issue? Routing is unlikely because you are just rendering the page. Not a syntax error, that would have triggered another error. Ok, so keep reading:
Rails.root: /Users/david/dev/testapp
Application Trace | Framework Trace | Full Trace
Now click "framework trace" and you will see:
activemodel (3.2.6) lib/active_model/naming.rb:163:in
model_name_from_record_or_class' activemodel (3.2.6) lib/active_model/naming.rb:158:in
param_key' actionpack (3.2.6) lib/action_view/helpers/form_helper.rb:369:in `form_for'
You may not understand all this -- few people do -- but you will see the error comes from model_name_from_record_or_class
which comes from param_key
which comes from form_for
. That is a big clue!
I recommend the use of the open_gem
gem to make it easy to dig into source code:
gem install open_gem
Now, take a look at activemodel, since it is the topmost gem in the stack trace:
gem open activemodel
Now, search for this with regular expression searching enabled:
def .*model_name_from_record_or_class
(Why? you want to find class methods -- e.g. definitions that start with self
as well.)
This will take you to line 162 in naming.rb
.
def self.model_name_from_record_or_class(record_or_class)
(record_or_class.is_a?(Class) ? record_or_class : convert_to_model(record_or_class).class).model_name
end
Even without understanding all of this, it does give a big hint... the method tries to return the model name from the record or class. Why can't it? Because the parameter you are passing, @user
, hasn't been set. The value of unset instance variables is nil, so it won't complain until you try to do something with it.
I hope this helps for this question and for future ones.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With