Showing error messages for nested resources in Rails - ruby-on-rails

I am creating my first app, simple blog, and I don't know how to show error messages for nested resource(comments) that doesn't pass validation.
this is create action for comments:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
redirect_to post_path(#post)
end
this is comment form:
<%= form_for([#post, #post.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
I tried with:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
if #comment.save
redirect_to post_path(#post)
else
render '/comments/_form'
end
end
and:
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#comment.errors.count, "error") %> prohibited
this comment from being saved:
</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
But I don't know whats wrong.

You can't render a partial from a controller. A better alternative is just to create a new view.
class CommentsController
def create
if #comment.save
redirect_to post_path(#post), success: 'comment created'
else
render :new
end
end
end
app/views/comments/new.html.erb:
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#comment.errors.count, "error") %> prohibited
this comment from being saved:
</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render partial: 'form', comment: #comment %>
app/views/comments/_form.html.erb:
<%= form_for([#post, local_assigns[:comment] || #post.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>

Related

Missing Parameters in Ruby on Rails

The Seller Profile has one seller. I am trying to post the seller profile details and assigning the seller_id to the current_seller. I am however, running into this error. I don't understand why the error says missing parameter because it seems all the needed params have being provided.
Error is get is ActionController::ParameterMissing (param is missing or the value is empty: seller_profiles
def create
#seller_profile = SellerProfile.new(seller_profile_params)
#seller_profile.seller = current_seller
respond_to do |format|
if #seller_profile.save
format.html { redirect_to root_path, notice: 'Seller profile was successfully created.' }
def seller_profile_params
params.require(:seller_profile).permit(:first_name, :other_name, :last_name, :email)
end
<%= form_tag seller_seller_profiles_path do |form| %>
<% if seller_profile.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(seller_profile.errors.count, "error") %> prohibited this seller_profile from being saved:</h2>
<ul>
<% seller_profile.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= label_tag :first_name %>
<%= text_field_tag :first_name %>
</div>
<div class="field">
<%= label_tag :other_name %>
<%= text_field_tag :other_name %>
</div>
<div class="field">
<%= label_tag :last_name %>
<%= text_field_tag :last_name %>
</div>
<div class="field">
<%= label_tag :email %>
<%= text_field_tag :email %>
</div>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>
resources :sellers, only: [:new, :create, :show, :index, :destroy] do
resources :seller_profiles
end
You should use the form_for or the form_with helpers instead of form_tag. Those helper methods will take care of adding the wrapping seller_profile key.
<%= form_for seller_profile do |form| %>
<% if seller_profile.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(seller_profile.errors.count, "error") %> prohibited this seller_profile from being saved:</h2>
<ul>
<% seller_profile.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :first_name %>
<%= form.text_field :first_name %>
</div>
<div class="field">
<%= form.label :other_name %>
<%= form.text_field :other_name %>
</div>
... replicate the same change for the rest of the fields ...
<div class="actions">
<%= form.submit %>
</div>
<% end %>
If the error is (param is missing or the value is empty: seller_profiles, it's because you require :seller_profile, not :seller_profiles in your params.require

Rails errors not showing?

So im learning rails, and following the rails getting started guide (I've actually done the "blog app" on the Udemy rails course, but im making sure I can write it from scratch first before moving on).
Anyways, i've gotten Delete/Create running, but I was adding validation...and while the validation works my errors aren't showing up.
Right now my pages are super simple:
new.html.erb
<% if #user.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved
</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_with scope: :user, url: users_path, local: true do |form| %>
<p>
<%= form.label :username %><br>
<%= form.text_field :username %>
</p>
<p>
<%= form.label :name %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.label :age %><br>
<%= form.number_field :age %>
</p>
<p><%= form.submit %></p>
<% end %>
users_controller
class UsersController < ApplicationController
def index
#users = User.all
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params.require(:user).permit(:username,:name,:age))
if #user.save
redirect_to users_path
else
render 'new'
end
end
def update
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_path
end
end
So the weird thing if I go into my network tab in dev tools I can see this show up in the response tab:
<div id="error_explanation">
<h2>
1 error prohibited this user from being saved
</h2>
<ul>
<li>Username has already been taken</li>
</ul>
</div>
But it doesn't show up in "elements" in Chrome dev tools. I've restarted rails....so Im really not sure why the elements are not showing up. I DO have bootstrap 4.00 beta installed, but not sure why that would matter. This is rails 5.1.4 btw.
This is because you are not getting the same #user in the <% if #user.errors.any? %>
Try this :
<%= form_with scope: :user, url: users_path, local: true do |form| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved
</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :username %><br>
<%= form.text_field :username %>
</p>
<p>
<%= form.label :name %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.label :age %><br>
<%= form.number_field :age %>
</p>
<p><%= form.submit %></p>
<% end %>

Rails: Hidden fields not passing values

I am trying to create a form for a site administrator to associate events with a list of previous speakers. The administrator navigates to the speaker, clicks on a button to "Add to event" and a form comes up asking for which event the speaker is attending. The speaker is supposed to be passed in as a hidden field, and the events are listed via a collection select. Unfortunately, the speaker id is not passing into the database when I submit the form.
Why is my form is not saving values from the hidden field, and how do I about fixing this? Values from the collection select are passing.
<%= form_for(#event_speaker) do |f| %>
<% if #event_speaker.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event_speaker.errors.count, "error") %> prohibited this event_speaker from being saved:</h2>
<ul>
<% #event_speaker.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p><%= #speaker.first_name %></p>
<div class="actions">
<%= #speaker.id %>
<%= f.hidden_field(:speaker) %>
<%= hidden_field_tag('speaker_id',#speaker.id) %>
</div>
<div class="field">
<%= f.label :event %><br>
<%= f.collection_select(:event_id, #upcoming_events, :id, :name)%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And the controller:
def new
#event_speaker = EventSpeaker.new
#speaker = Speaker.find(params[:speaker_id])
#event_speaker.speaker_id = #speaker
#Time = Time.now
#upcoming_events = Event.all
end
# GET /event_speakers/1/edit
def edit
end
# POST /event_speakers
# POST /event_speakers.json
def create
#event_speaker = EventSpeaker.new(event_speaker_params)
respond_to do |format|
if #event_speaker.save
format.html { redirect_to #event_speaker, notice: 'Event speaker was successfully created.' }
format.json { render action: 'show', status: :created, location: #event_speaker }
else
format.html { render action: 'new' }
format.json { render json: #event_speaker.errors, status: :unprocessable_entity }
end
end
end
And...
def event_speaker_params
params.require(:event_speaker).permit(:speaker_id,:event_id)
end
You should do
<%= f.hidden_field :speaker_id, :value => #speaker.id %>
This will generate your speaker_id nested inside event_speaker so your form will look like this:
<%= form_for(#event_speaker) do |f| %>
<% if #event_speaker.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event_speaker.errors.count, "error") %> prohibited this event_speaker from being saved:</h2>
<ul>
<% #event_speaker.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p><%= #speaker.first_name %></p>
<div class="actions">
<%= f.hidden_field :speaker_id, :value => #speaker.id %>
</div>
<div class="field">
<%= f.label :event %><br>
<%= f.collection_select(:event_id, #upcoming_events, :id, :name)%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
For details checkout hidden field in rails

Errors for nested resource not displaying even if I'm using "target"?

I have the following:
routes.rb:
resources :posts do
resources :replies
end
replies_controller.rb:
class RepliesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#reply = #post.replies.build(params[:reply])
#reply.user_id = current_user.id
if #reply.save
flash[:success] = "reply created!"
redirect_to post_path(#post)
else
redirect_to post_path(#post)
end
end
replies/_form.html.erb:
<%= form_for([#post, #post.replies.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object, target: #reply %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
posts/show.html.erb:
<div class="span8">
<%= render 'replies/form' %>
</div>
shared/error_messages.html.erb:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I'm not sure why the errors messages for the replies are not displaying since I'm using target: #reply (:content and :user_id are required).
Any suggestions to fix this?
In create method's else section you have to render the post_path(#post) not redirect the post_path(#post)
try this in else part of create section
render :template => 'posts/show'
So that your current #reply object will persist for your error messages.
redirect_to post_path(#post) will redefine #reply object in show action (I assume you have defined #reply object there).
In posts/show action, build your reply object there and assign it to #reply instance object.
#reply = #post.replies.build
Now in replies/_form.html.erb:
change #post.replies.build to #reply
i.e
<%= form_for([#post, #post.replies.build]) do |f| %>
to
<%= form_for([#post, #reply]) do |f| %>
Also assign #reply to object variable while rendering 'shared/error_messages' partial,
<%= form_for([#post, #reply]) do |f| %>
<%= render :partial => 'shared/error_messages', :locals => {:object => #reply} %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
Also make partial for error_messages in shared folder (shared/_error_messages). In this partial paste your code which is in shared/error_messages
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>

How to populate form in nested model when error occurs?

Running Rails 3.2.1.
I went through the "Getting started" guide on the Ruby on Rails site. I have set up a blog post where someone can comment on the posts.
I modified the example to show an error when I enter in comments that don't validate (no name or comment text).
(A post has multiple comments, etc.)
However, how do I have Rails put this problematic comment back in the form, instead of the page?
Here is my create method in the comments controller:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#post, :notice => 'Comment was successfully created.') }
else
format.html { render 'posts/show' }
end
end
end
Here is my show.html.erb from posts:
<%= render #post %>
<h3>Comments</h3>
<%= render #post.comments %>
<h3>Add a comment</h3>
<%= render "comments/form" %>
<p>
<% if user_signed_in? %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<% end %>
<%= link_to 'Back', posts_path %>
</p>
And here is my comment form partial:
<%= form_for([#post, #post.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label "Name" %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit "Add Comment!" %>
</div>
<% end %>
And here's my comment partial:
<p>
<strong><%= comment.name %></strong><br />
<%= comment.created_at.try(:strftime, "on %A, %B %d %Y at %H:%M:%S") %><br />
<%= simple_format(h(comment.body), :sanitize => true) %>
</p>
In your form when you return from an error.
<% if #comment.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Resources