Rails: one view, model and it's associated model - ruby-on-rails

So, for example, case from http://guides.rubyonrails.org/getting_started.html As you can see, if you try to create invalid post, you will see error messages:
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.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 :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
How to implement error messages rendering for associated Comment model, keeping in mind that comment creation form is placed in posts/show view?

Form code is usually kept in the folder of the matching model in a _form.html.erb partial that is rendered in both new.html.erb and edit.html.erb (to see a good example, generate a scaffold for a sample model).
What you can do in your case is render this comments form partial in the posts show action.
app/views/posts/show.html.erb
<%= render 'comments/form', comment: #comment || #post.comments.build # Whatever you have here %>
app/views/comments/_form.html.erb
<%= form_for comment do |f| %>
<%= render 'error_messages', target: comment %>
...
<% end %>
In addition, showing error messages usually is the same in all forms, so in order to remove duplication, you can extract this code into a seperate partial.
app/views/application/error_messages.html.slim # here is slim syntax, convert as nescessary
/ error explanation
/
/ = render 'shared/error_explanation', target: #school
/
- if target.errors.any?
.error-messages
h4 Please correct the following fields:
ul
- target.errors.full_messages.each do |message|
li = message
Hope this helps.

Related

Showing associated model errors in Rails 6 form

I'm using Rails 6.0.3.4 and Ruby 2.7.2. Using the Rails getting started tutorial as an example, I'm wondering how to show form validation errors of an associated model.
Show page
<p>
<strong>Title:</strong>
<%= #article.title %>
</p>
<p>
<strong>Text:</strong>
<%= #article.text %>
</p>
<h2>Comments</h2>
<%= render #article.comments %>
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
<%= link_to 'Edit', edit_article_path(#article) %> |
<%= link_to 'Back', articles_path %>
Comments form (this is the form in question)
<%= form_with(model: [ #article, #article.comments.build ], local: true) do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_field :commenter %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
Models
class Comment < ApplicationRecord
belongs_to :article
validates :commenter, presence: true
end
class Article < ApplicationRecord
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5 }
end
For a single model articles form, errors could be shown like this.
<% 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 %>
How do I show errors for the comments form? When I submit a comment without a commentor, it does not save, so validations are happening, but I'm not sure how to show errors for this type of form.
<% if #???????.errors.any? %> ###### What do I say here to get the comment errors?
<div id="error_explanation">
<h2>
<%= pluralize(#?????.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #?????.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
1. Create a reusable partial for errors
# app/views/shared/_errors.html.erb
<div class="error_explanation">
<h2><%= pluralize(object.errors.count, "error") %> prohibited
this <%= object.model_name.singular %> from being saved:</h2>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
And a little helper method:
# app/helpers/application_helper.rb
module ApplicationHelper
# Displays the errors for a model instance if there are any
def display_errors_for(object)
return unless object.errors.any?
render partial: 'shared/errors',
locals: { object: object }
end
end
2. Get the object from the form builder
You can always access the model wrapped by the form builder instance through the #object method instead of using a instance variable:
<%= form_with(model: [ #article, #comment ], local: true) do |form| %>
# ...
<%= display_errors_for(form.object) %>
<% end %>
And like magic you can add errors to any form with a single line.
Do not use #article.comments.build. That will always bind the form to a new instance of comment instead of displaying the errors! It will also remove anything the user entered into the form... Assign the variable in the controller. I have no idea how this snuck its way into the guides.
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
#comment = #article.comments.new
end
end

Ruby on Rails: Encountered a syntax error while rendering template:

Good night.
I'm doing the getting started guide of RoR, but I have a trouble:
When I click the New Article button that redirects to the form, Rails throw an 'Encountered a syntax error while rendering template.'
The new.html.erb code is
<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 %>
The code is the same as the guide's code, so i don't know where the error or errors can be.
I also attach the error screenshot if it's any help.
Rails error message when I want tho create a new Article
Here two problems:
wrong syntax in if condition (don't need to use =)
extra \n chars in your screenshot
Change your 5 line in app/view/articles/new.html.erb to:
<% if #article.errors.any? %>
<% %> executes Ruby code
<%= %> executes Ruby code and prints out
Also read about the difference on SO

Instance variable nil in one view, not in another

I'm working on a project in Ruby on Rails (Ruby v.2.2.8, Rails 5.1.4) and have encountered a very strange issue.
For my show method in the controller, I have:
def show
#county = County.find(params[:id])
end
And it works. For update, I have.
def update
#county = County.find(params[:id])
if #county.update(county_params)
redirect_to #county
else
render 'edit'
end
end
In my 'edit', I consistently get an error that #county is nil. The error page indicates that the parameters are being passed as:
{'id'=>4}
as an example. When I use find_by from the rails console, the item is found.
Is there something here I'm missing?
ETA: View Code
<%= form_with model: #county, local: true do |form| %>
<% if #county.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#county.errors.count, "error") %> prohibited
this county from being saved:
</h2>
<ul>
<% #county.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :name %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.label :shortname %><br>
<%= form.text_field :shortname %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
ETA Routes for Counties:
counties GET /counties(.:format) counties#index
POST /counties(.:format) counties#create
new_county GET /counties/new(.:format) counties#new
edit_county GET /counties/:id/edit(.:format) counties#edit
county GET /counties/:id(.:format) counties#show
PATCH /counties/:id(.:format) counties#update
PUT /counties/:id(.:format) counties#update
DELETE /counties/:id(.:format) counties#destroy
The error occurs at /counties/:id/edit
How is your edit action in your controller?
You should define #county as well
def edit
#county = County.find(params[:id])
end

ActionView::TemplateMissing error in Rails 4 when rendering shared errors

I'm learning Rails and am implementing an app for which I decided to go through the Site Point tutorial.
According to it, I've done the following in apps/views/users/new.html.erb
<%= form_for #user do |f| %>
<%= render 'shared/errors', object: #user %> #=> error
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, placeholder: 'Your display name', class: 'form-control', required: true %>
</div>
<% end %>
But I'm getting
ActionController:MissingTemplate in Users#new
How can I get rid of it? I've posted the full trace here
The tutorial you're following assumes you have an _errors.html.erb file in the app/views/shared directory.
<%= render 'shared/errors', object: #user %>
That line of code is trying to render that partial and pass #user which will be used in the partial.
If you want to remove that error then remove that line of code. If you want to display those errors then create the relevant file and read up on how to display errors in the view.
<% if object.errors.any? %>
<div id="error_explanation">
<ol>
<% object.errors.full_messages.each do |msg| %>
<li class="alert alert-danger"><%= msg %></li>
<% end %>
</ol>
</div>
<% end %>
Put this in your app/views/shared/_errors.html.erb

Submit a form to a model from my homepage

I have a links model which has all the generic scaffold created for it, however, rather than go to the link#new page, I'd like to submit a form from my homepage that populates a new record.
I only have one text field, but im not sure how to construct the form. I read somewhere you have to specify the controller in the form field but this doesn't appear to be working.
<%= form_for(:link, #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 :url %><br />
<%= f.text_field :url %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You don't need to specify anything if you are using default routes.
If the #link is an object that doesn't exist in database, Rails will automatically think this is a form for #new. So the form action will be /links, and method is post, which is the default resource to #create
In your case, you don't need to do anything, just revise the form code to:
<%= form_for(#link) do |f| %>
....
Besides, you need to prepare #link object in home controller, something like
#link = Link.new
All you have to do is add a url parameter to the form_for helper
<%= form_for :link, url: your_home_path do |f| %>

Resources