I am trying to complete the official Rails tutorial and on step 5.2. The instructions are to do a form_with, but i got an error, looked up this StackOverflow post:
Rails form_with results in a NoMethodError. I changed the form_with
to form_for
like the answer said, and i get this error:
Showing /home/ubuntu/workspace/app/views/articles/new.html.erb where line #2 raised:
undefined method 'model_name' for {:scope=>:article, :url=>"/articles", :local=>true}:Hash
Extracted source (around line #2):
1. <h1>New Article</h1>
2. <%= form_for scope: :article, url: articles_path, local: true do |form| %>
3. <p>
4. <%= form.label :title %><br>
5. <%= form.text_field :title %>
6. </p>
Rails.root: /home/ubuntu/workspace
app/views/articles/new.html.erb:2:in '_app_views_articles_new_html_erb__1707235537542743350_40377020'
I am using Cloud9, if it helps. Here is my code for the view and controller:
View:
<h1>New Article</h1>
<%= form_for scope: :article, url: articles_path, local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
Controller:
class ArticlesController < ApplicationController
def new
end
def create
render plain: params[:article].inspect
end
end
I would have thought your ArticleController
would look like:
class ArticlesController < ApplicationController
def new
@article = Article.new
end
def create
render plain: params[:article].inspect
end
end
And your view would look like:
<h1>New Article</h1>
<%= form_for @article do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
Given an @article
, form_for
will correctly infer the url as long as:
the record passed to form_for is a resource, i.e. it corresponds to a set of RESTful routes, e.g. defined using the resources method in config/routes.rb
According to the docs.
It is also worth noting, perhaps, that the signature for form_for
is (again, according to the docs):
form_for(record, options = {}, &block)
Which means that form_for
expects to be passed (1) a record, (2) zero or more options, and (3) a block. A 'record' can actually be one of a number of things (such as an instance, a string, or a symbol), as described in the docs.
When you do:
<%= form_for scope: :article, url: articles_path, local: true do |form| %>
I believe what is going on is that form_for
is accepting the hash {scope: :article, url: articles_path, local: true}
as the record and attempting to infer the url by calling model_name
on the hash. A hash, naturally, does not respond to model_name
, and so you get:
undefined method 'model_name' for {:scope=>:article, :url=>"/articles", :local=>true}:Hash