Rails - Simple Form - style error messages - ruby-on-rails

I'm trying to make a partial in my views folder, which his shared for error messages.
I want to remove the simple form standard error message and replace it with my own styling - across all models.
My question is, how do I reference the relevant model in my partial. Depending on where its used, it needs to reference the form in which the partial is included.
For example, the standard simple form error block is:
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project_question.errors.count, "error") %> prohibited this question from being
saved:</h2>
<ul>
<% #project_question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
How do I replace #question, with #[whatever the relevant model is called]?
Thank you

For this you can make a partial _error_messages,html.erb
<% if model.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(model.errors.count, "error") %> prohibited
this from being saved:
</h2>
<ul>
<% model.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
And you can render this partial in your view as:
<%= render partial: "error_messages", locals: {model: #question} %>

Your answer is a passing a local variable http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
<%= render partial: "your_partial", locals: {question: #question} %>

Related

create instance variable in erb template

Say I have 2 erb views: a list view and a show view, I want to render the show view inside the list view
list view
<% #vehicles.each do |vehicle| %>
<h2><%= vehicle.type %></h2>
<ul>
<% vehicle.accessories.each do |accessory| %>
<li><% accessory.title %></li>
<% end %>
</ul>
<% end %>
show view
<h2><%= #vehicle.type %></h2>
<ul>
<% #vehicle.accessories.each do |accessory| %>
<li><% accessory.title %></li>
<% end %>
</ul>
the issue is the show view takes an #vehicle instance variable, how can I pass that down from the parent if I was going to nest these and it still shows up as an instance variable, accessed with #vehicle? something like:
<% #vehicles.each do |vehicle| %>
<%= render "show" %>
<% end %>
I guess you might want to make that show view a partial. Something like:
<h2><%= vehicle.type %></h2>
<ul>
<% vehicle.accessories.each do |accessory| %>
<li><% accessory.title %></li>
<% end %>
</ul>
Then you can do something like:
<% #vehicles.each do |vehicle| %>
<%= render "path/to/show_partial", locals: {vehicle: vehicle} %>
<% end %>
Naturally, you'll want to:
use the real path/to/show_partial, whever that happens to be, and
do some eager loading so that you're not doing a whole bunch of N+1 queries.

How to display errors on a form_for with multiple resources

I have an order form where I can add order items
<h2>Order: <%= #order.title %></h2>
<h3>Items</h3>
<%= render #order.items %>
<h4>Add an item:</h4>
<%= form_for([#order, #order.items.build]) do |f| %>
<%= f.label :Item %>
<%= f.submit 'Submit' %>
<% end %>
I want to check if there are any errors when creating the item.
This is what I use on the order form:
<% if #order.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#order.errors.count, "error") %> prohibited
this order from being saved:
</h2>
<ul>
<% #order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I don't know how to display errors when there is multiple resources in the form for.
I've run into this before and ended up wanting to really customize the messages. In order to do it, I used a solution like this:
<% if #errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#errors.count, "error") %> prohibited
this order from being saved:
</h2>
<ul>
<% #errors.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
This allows you to create an #errors object in your controller where you build array of messages. For example something like this:
#errors = []
#errors += #order.errors.map(&:full_messages)
#errors += #items.map(&:errors).map(&:full_messages).flatten
...
I hope this helps!

Control Structure in Rails Partial

I'm building a Rails app up from the Sample App featured in Michael Hartl's book. In order to display error messages on user signup, I'm using a partial in the shared directory - app/views/shared/_error_messages.html.erb:
<%if #fact %>
<% #data = #fact %>
<% elsif #user %>
<% #data = #user %>
<% end %>
<% if #data.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(#data.errors.count, "error") %>.
</div>
<ul>
<% #data.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Originally, this partial just started with something like:
<% if #user.errors.any? %>
However, since I've decided to re-use this partial to show errors on other pages, I'm having to use different objects (#user, #fact) depending on which page I'm using it on. This is easily solved by adding that IF statement at the top,
<%if #fact %>
<% #data = #fact %>
<% elsif #user %>
<% #data = #user %>
<% end %>
-but this feels icky. Is there a controller somewhere I should be putting this kind of logic for shared partials?
You can pass local variables to partial instead:
<% 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 %>
And in your template, for example:
<%= render 'shared/error_messages', object: #user %>
Marek's answer is probably the best. However, here is an alternative which though not scalable, is closer to what you have done.
Just replace:
<%if #fact %>
<% #data = #fact %>
<% elsif #user %>
<% #data = #user %>
<% end %>
with:
<% #data = #fact||#user %>
You could use render to point to the partial from your controllers for users and fact. Check out the API documentation on rendering partials.

Accessing Object within Form - Rails

i try to access the first element of a array within my #user object and get the first object
out of that array. I just bring it not to work. Here is the code:
<%= form_for(#user) do |f| %>
<% 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 %>
<% if params[:redirect_to] -%>
<%= hidden_field_tag 'redirect_to', params[:redirect_to] %>
<% end -%>
#Thats not working
Last booking: <%= f.text_field Booking.where("user_id="+ #user.id+").order('start_date DESC').first%>
<% end %>
First of all You are trying to push a whole Booking object into the field, which seems to be wrong, probably You want some particular value like booking_date or something like this.
Booking.where(user_id: #user.id).order(:start_date).last.booking_date
Secondly You have a syntax error there and text_field method expects name of the user model field. If You defined has_many :bookings then You should use fields_for. Remember if You use form_for form builder You must reference model fields, if You need something custom use text_field_tag instead.
text_field_tag :booking, Booking.where(user_id: #user.id).order(:start_date).last.booking_date

Ruby On Rails - Reusing the error message partial view

Problem
I was trying to reuse the Error Message block in my Views.
Below was the block written in positions/_error_messages.html.erb
<% if #position.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(#position.errors.count, "error") %>.
</div>
<ul>
<% #position.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
The problem was I have to created similar partial view in every Model which is kind of repeating the same code with different object i.e. #user, #client etc.
Remedy
I have created one erb in shared folder shared/_error_messages.html.erb and wrote the below code.
<% def error_message(active_object) %>
<% if active_object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(active_object.errors.count, "error") %>.
</div>
<ul>
<% active_object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
and then in view file. positions/new.html.erb I wrote the below code
<div id="errorbox">
<%= render "shared/error_messages" %>
<%= error_message(#position) %>
</div>
It means now I can use the same code in all my Create and Update operations.
I want to know, Is that a correct way to do it? Or is there any other option?
No, defining methods in views is not correct way to do it. I think you should rather substitute #position from your first partial with local variable named in more generic way, for example object and render this partial with:
<%= render 'shared/error_messages', object: #position %>
which passes #position as local variable object to the partial.
<%= render partial: 'shared/error_messages', locals: {position: #position} %>
Now in your partial _error_messages.html.erb in the shared folder you can use the position variable.
Refer to http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html for more help.
It's not the best way to do it.
replace #position with something more generic like 'obj' (as an example) in your first block of code. So it will look like this.
<% if obj.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(obj.errors.count, "error") %>.
</div>
<ul>
<% obj.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
All you did there was replace #position with obj.
Now take the above code, and put it inside your shared folder as '_error_messages.html.erb'
Now for every file where you need the error messages you can render the partial and replace obj with whatever instance variable is used in that file. (at this point you would replace any error message code in your files with the code below, depending on which instance variable you are using. examples below)
in positions:
<%= render 'shared/error_messages', obj: #position %>
in user:
<%= render 'shared/error_messages', obj: #user %>
in client:
<%= render 'shared/error_messages', obj: #client %>
etc...
the obj: #client #or any instance variable
switches out the 'obj' of the partial and puts in the instance variable in it's place. Hope that helps!

Resources