I have a table pages and a table author. Each page belongs to one author. Created migrations for the tables and models as well. But getting this error while using it in form:
NoMethodError in Pages#new
Showing C:/rorapp/app/views/pages/_form.html.erb where line #1 raised:
undefined method `build' for nil:NilClass
Extracted source (around line #1):
1: <%= form_for(#page, #page.author.build) do |f| %>
2: <% if #page.errors.any? %>
3: <div id="error_explanation">
4: <h2><%= pluralize(#page.errors.count, "error") %> prohibited this post from being saved:</h2>
Trace of template inclusion: app/views/pages/new.html.erb
Rails.root: C:/rorapp
Application Trace | Framework Trace | Full Trace
app/views/pages/_form.html.erb:1:in `_app_views_pages__form_html_erb___998576952_54480300'
app/views/pages/new.html.erb:2:in `_app_views_pages_new_html_erb__638997451_40207104'
Request
Parameters:
None
Show session dump
Show env dump
Response
Headers:
None
Here is my model file for author:
class Author < ActiveRecord::Base
has_one :page
end
And page model:
class Page < ActiveRecord::Base
validates :title, :presence => true
belongs_to :author
end
And here is the snippet of model form :
<%= form_for(#page, #page.author.build) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
Any ideas how to go ahead with it?
thanks
EDIT - 1
Here is my action method called new :
def new
#page = Page.new
#page.build_author
end
And here is the form it is rendering:
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.label :author %><br />
<%= f.text_field :author %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :reference %><br />
<%= f.select(:reference,[['google',1],['yahoo',2],['MSN',3],['Ask',4]]) %>
</p>
<%= f.submit "Submit" %>
<% end %>
EDIT - 2
Here is my controller code:
class PagesController < ApplicationController
def index
#total = Page.count
#pages = Page.find(:all)
end
def show
#page = Page.find(params[:id])
end
def new
#page = Page.new
#page.build_author
end
def create
#page = Page.new(params[:page])
if #page.save
redirect_to pages_path, :notice => "The data has been saved!"
else
render "new"
end
end
def edit
#page = Page.find(params[:id])
end
def update
#page = Page.find(params[:id])
if #page.update_attributes(params[:page])
redirect_to pages_path, :notice => "Your post has been updated!"
else
render "edit"
end
end
def destroy
#page = Page.find(params[:id])
#page.destroy
redirect_to pages_path, :notice => "Your page has been deleted!"
end
end
you need to add *#page.build_author* in the new action of pages controller.
def new
#page = Page.new
#page.build_author
respond_to do |format|
format.html # new.html.erb
format.json { render json: #page }
end
end
It should be #page.build_author instead of #page.author.build. But the logic of this still doesn't look right to me.
Related
Good Morning.
I'm following the tutorial http://edgeguides.rubyonrails.org/getting_started.html and I find the following:
I have a controller called ArticlesController. The create method uses the "if # article.save" statement to save the #article object, and if something goes wrong then render 'new'. Similarly the update method uses "if #article.update (article_params)" to update the record for that article, and if something goes wrong render 'edit'.
In new and edit views <% if # article.errors.any? %> is used to determine if there was any error and display the corresponding message, but the problem is that in the new view works fine, but in the edit view #article.errors.any view? returns false even if there is an error.
Can someone tell me what's wrong. Thank you very much.
Then I put the ArticlesController class, the views new.html.erb and edit.html.erb, and the article model.
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
------------------------------------------------------------------
<h1>New Article</h1>
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<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 %>
<%= link_to 'Back', articles_path %>
----------------------------------------------------------------------
<h1>Edit article</h1>
<%= form_with(model: #article) do |form| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<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 %>
<%= link_to 'Back', articles_path %>
---------------------------------------------------------------------
class Article < ApplicationRecord
validates :title, presence: true,
length: { minimum: 5 }
validates :text, presence: true
end
All forms generated by form_with will be submitted by an XHR (Ajax) request by default. if you want to disable remote forms then you can do it with local like you did in the form in new.html.erb.
change this in your edit.html.erb :
<%= form_with model: #article, local: true do |form| %>
It's a limitation of Turbolinks, which does not work with render
See here https://joey.io/turbolinks-rendering-form-errors/ and here https://github.com/jorgemanrubia/turbolinks_render
Got the same error today. They are using render with form_with in their documentation but it doesn't work.
I used form_for and it fixed the problem.
<%= form_for article do |form| %>
I am having trouble passing an instance variable (#article) from a controller (articles_controller.rb) to a partial render (_form.html.erb) in Ruby.
Here is the error from being sent back:
`undefined method `errors' for nil:NilClass`
articles_controller.rb:
class ArticlesController < ApplicationController
def new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit', :article => #article
end
end
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
new.html.erb
<h1>New Article</h1>
<%= form_for :article, url: articles_path do |f|%>
<%= render partial: "form", :locals => {:article => #article} %>
<% end %>
<% link_to 'Back', articles_path %>
_form.html.erb
<% if #article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#article.errors.count, "error") %> prohibited this
article from being saved:
</h2>
<ul>
<% #article.errors.full_messeages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
Any help would be appreciated
def new
#article = Article.new
end
<%= render partial: "form", collection: #article %>
or even
<%= form_for #article do |f|%>
<%= render 'form' %>
<% end %>
depends on your needs
I had this challenge when working on a Rails 6 application.
I wanted to use an instance variable in a partial (app/views/shared/_header.html.erb) that was defined in a different controller (app/controllers/categories_controller.rb).
Here's how I did it:
The instance variable that I wanted to use is #categories which is defined as:
# app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
.
.
.
end
Firstly, I rendered the app/views/shared/_header.html.erb partial in the app/views/layouts/application.html.erb and passed the #categories instance variable into it this way:
<%= render partial: '/shared/header', locals: { categories: #categories } %>
And then I used the instance variable in the partial this way:
# app/views/shared/_header.html.erb
<% #categories.each do |category| %>
<%= link_to category do %>
<%= category.name %>
<% end %>
<% end %>
However, this will require a controller action that sets a #categories instance variable for every controller views that will use the partial.
If you want to make variables globally available in your controllers and views, this could help: Rails: Set a common or global instance variable across several controller actions
That's all.
I hope this helps
You should do like this, removing #. You are passing it to local variable article so you could access it with article not #article:
<% if article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(article.errors.count, "error") %> prohibited this
article from being saved:
</h2>
<ul>
<% article.errors.full_messeages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
For more info, please take a look at passing-local-variables
when i click new post and try to save a new post it gives me that error, then i go to the controller :
private
def posts_params
params.require(:post).permit(:title, :description)
end
and change 'require(:post)' to 'require(:posts' then i works
but then i try to edit the new post i just created and when i click to save it it gives me the same error, then i just change it back to 'required(:post)' and it works, why this is happening ? it's like a loop, if one works the other doesn't and to work i have to change that one thing
Controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def edit
#posts = Post.find(params[:id])
end
def update
#posts = Post.find(params[:id])
if #posts.update(posts_params)
redirect_to #posts
else
render 'edit'
end
end
def new
#posts = Post.new
end
def create
#posts = Post.new(posts_params)
if #posts.save
redirect_to #posts
else
render 'new'
end
end
def show
#posts = Post.find(params[:id])
end
private
def posts_params
params.require(:post).permit(:title, :description)
end
end
view edit:
<h1>Editing post</h1>
<%= form_for(#posts) do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
view new:
<h1>New Article</h1>
<%= form_for :posts, url: posts_path do |f| %>
<% if #posts.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#posts.errors.count, "error") %> prohibited
this post from being saved:
</h2>
<ul>
<% #posts.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', posts_path %>
can someone point the problem out ?
You are mixing
form_for(#posts) do |f|
and
form_for :posts, url: posts_path
In your forms.
the :posts version will generate params[:posts] and the #posts version will generate params[:post]. Hence the issue you are seeing. Make sure you posts_params is as follows.
def posts_params
params.require(:post).permit(:title, :description)
end
then just change both of your forms to be
<%= form_for(#posts) do |f| %>
rails will figure out which to call automatically for you, so you will not have to specify the paths..
On a side note, I would probably change #posts to be #post everywhere but the index action, just so that it makes more sense, Since in new,edit,etc.. you are dealing with a singular post.
Since rails is looking at the Model/class of the variable when generating the routes (When given an instance variable) the name of the variable doesn't matter to the framework, but makes it easier (in my opinion) for the programmer to understand
I'm trying to build Reddit on Rails by Schneems. And I keep getting this error at the point of submitting a new link.
ruby 1.9.3
Rails 4.2.0
What's wrong with my Links#Controller ?
class LinksController < ApplicationController
def show
#link = Link.find(params[:id])
end
def new
#link = Link.new
end
def create
#link = Link.new(links_params)
if #link.save
redirect_to(:action => 'show')
else
render('new')
end
end
private
def links_params
params.require(:link).permit(:title, :url)
end
end
The code should take me to a page showing submitted title and url. But it gives me :
ActiveRecord::RecordNotFound in LinksController#show
Couldn't find Link without an ID
Rails.root: C:/Users/Andrew/Documents/reddit_on_rails
Application Trace | Framework Trace | Full Trace
app/controllers/links_controller.rb:4:in `show'
New view is:
<h1>New link</h1>
<%= form_for #link do |f| %>
<% if #link.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#link.errors.count, "error") %> prohibited this link from being saved:</h2>
<ul>
<% #link.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :url %><br />
<%= f.text_field :url %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I've already added strong params to bundler but that did nothing.
I fixed it after four days(finally!).
So links controller should look like this:
def create
#link = Link.new(links_params)
if #link.save
render('show')
else
render('new')
end
Because before it was taking me to page localhost:3000/links/show and I needed localhost:3000/links/id
I don't get why the form is not validated. create method is executed even if there are no values in the text fields here is the code that I use
class MoviesController < ApplicationController
def new
#movie = Movie.new
#movies = Movie.find(:all)
end
def create
#movie = Movie.new(params[:movie])
if #movie.save
redirect_to "http://localhost:3000/movies/new/"
end
end
end
Model
class Movie < ActiveRecord::Base
attr_accessible :title, :year
validates_presence_of :title
validates_presence_of :year
end
Here is the view
Enter new movie information
<%= form_for #movie do |f|%><br />
Title <%= f.text_field :title %><br />
Year <%= f.text_field :year %><br />
<%= f.submit %>
<% end %>
<hr />
List of all movies<br />
<% if !#movies.blank? %>
<% for item in #movies %>
<%= item.id %> <%= item.title %> (<%= item.year %>) <br />
<% end %>
<% else %>
<% end %>
In Controller
def create
#movie = Movie.new(params[:movie])
if #movie.save
redirect_to new_movie_path # You sure you what to redirect this to new after success?
# redirect as per your project requirement on success
else
render :new # render new with errors displayed
end
end
In View added error display message when validation fails
<%= form_for #movie do |f|%>
<% if #movie.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#movie.errors.count, "error") %> prohibited this from being saved:</h2>
<ul>
<% #movie.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<br />
Title <%= f.text_field :title %><br />
Year <%= f.text_field :year %><br />
<%= f.submit %>
<% end %>
<hr />
List of all movies<br />
<% if !#movies.blank? %>
<% for item in #movies %>
<%= item.id %> <%= item.title %> (<%= item.year %>) <br />
<% end %>
<% else %>
No Movies found.
<% end %>
The validation occurs when you call #movie.save. Because #movie is not valid, #save will return false and #movie.errors will be populated.
This validation does not prevent the form being submitted (and #create being executed). For that you want to look at validations with JavaScript/jQuery and Rails.