Ruby On Rails - Reusing the error message partial view - ruby-on-rails

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!

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.

Rails - Simple Form - style error messages

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} %>

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.

undefined local variable or method `object' for error_messages.html

I'm following the ruby on rails tutorial. And I received a error on my signup page only.
undefined local variable or method `object' for #<#<Class:0x007feb442f6a98>:0x007feb442f8438>
Extracted source (around line #1):
1: <% if object.errors.any? %>
2: <div id="error_explanation">
3: <h2>
4: <%= pluralize(object.errors.count, "error") %>
Here's my error_messages file.
<% if object.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(object.errors.count, "error") %>
prohibited this <%= object.class.to_s.underscore.humanize.downcase %> from being saved:
</h2>
<p>There were problems with the following fields:</p>
<ul>
<% object.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
Now here's my users/new.html file.
<h1>Sign up</h1>
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<%= render 'fields', :f => f %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
The object passed down with :object => becomes a local variable in the partial with the same name as the partial. So in this case, where your partial is called error_messages, the first line should be
<% if error_messages.errors.any %>
Now obviously this looks a little confusing - which is perhaps a suggestion the naming of the partial is wrong.
Also, partial view files should be named starting with an underscore - shared/_error_messages - to mark they're not full views; they should be rendered with render :partial => 'shared/error_messages'; and the :object local variable doesn't carry the underscore.
See some docs on rendering partials.

ruby on rails shared error message cannot define method or object

I've been reading through the ruby on rails tutorial by michael hartl, and i'm at where I am trying to post microposts. I'm trying to render an error message within the form, and the book says to assign f.object to object. It keeps giving me the error that "object" is an undefined local variable or method. Here is the code:
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 %>
shared/_post_form.html.erb
<%= form_for(#post) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new post..." %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
UPDATE:
The answer below is incorrect. See the comments for details.
ORIGINAL ANSWER:
I'm not sure what Hartl's tutorial says, but f.object is not defined on the form, which I assume is where the error is coming from (please post the error itself for clarity).
Changing this line:
<%= render 'shared/error_messages', object: f.object %>
to
<%= render 'shared/error_messages', object: f %>
Should fix the problem. Basically you want to pass the form f to the partial, with the name object -- that's what the option object: f does. (You could actually name it anything you want, as long as you use the same naming inside your partial. There's nothing special about the name object in this context.)
Hope that helps.
Maybe you forgot pass a #post form controller. Where controller are you in when you render partial _post_form.html.erb ? Check if you don't have a #post = current_user.posts.build in that controller, add it.

Resources