Cannot render partial of another module and pass variables - ruby-on-rails

I am sorry in advance as I know this should be an easy one but I am stuck. I have a show view for "Category" in which I am trying to display related has_many "Subcategories". I am calling the partial by using the following:
<%= render partial: 'subcategories/subcategory', locals: {category: #category }%>
I have an html file in the Subcategories view folder properly named and the partial view loads. I know this because the partial has the code
<%= #category.name %></p>
which shows the correct Category name within the partial. However, when I try to load any of the subcategory data by calling
<% #subcategories.each do |subcategory| %>
<%= subcategory.name%>
<% end %>
I get the error: NoMethodError in Categories#show, undefined method `each' for nil:NilClass
I'm sorry to ask such a basic question but I will be using partials from related modules extensively in this project.

Replace this:
<%= render partial: 'subcategories/subcategory', locals: {category: #category }%>
with this:
<%= render #category.subcategories %>
Then in the partial app/views/subcategories/_subcategory.html.erb do this:
<%= subcategory.name %>

Related

RoR: How to define a method for a partial?

I am trying to render a partial on a page...like so
../devise/sessions/new.html.erb
<%= render partial: '/tweets/latest_tweets' %>
All good
In the partial I would like to do "each do" like so...
../tweets/_latest_tweets.html.erb
<% #tweets.each do |tweet| %>
<%= tweet.content %>
<% end %>
I get undefined method `each' for nil:NilClass
How do I define this method for my partial in my tweets controller?
I have index like so
tweets_controller.rb
def index
#tweets = Tweet.all
end
Which is fine for the index but I don't know how to do same for my partial (I tried just defining my partial like the index but that did not seem to work)
Anyone have a solution I could try?
ty
You need to pass the collection when rendering the partial. It'll give something like this:
devise/sessions/new.html.erb
<%= render partial: 'tweets/latest_tweets', collection: #tweets, as: :tweet %>
tweets/_latest_tweets.html.erb
<%= tweet.content %>
Just like that, and it will iterate through your collection automatically.
Fore more info, please read Rails - Layout and Rendering

How Rails render finds variable

Simple example:
index.html.erb:
<% #posts.each do |post| %>
<%= post.title %>
<% end %>
I can refactor this and move content to the _post.html.erb partial:
index.html.erb:
<%= render #posts %>
_post.html.erb:
<%= post.title %>
So how Rails passes attributes of every post without creating a block?
My posts_controller index action has only #posts = Post.all defined.
I thought that maybe by the name of the partial (post), but looks like its another Rails convention (plural and singular naming). Is it?
Many thanks for sharing!
Rails determines the name of the partial to use by looking at the model name in the collection. The full syntax to render a collection is as follows:
<%= render partial: "post", collection: #posts %>
However there is a shorthand for this:
<%= render #posts %>
According to docs:
When a partial is called with a pluralized collection, then the
individual instances of the partial have access to the member of the
collection being rendered via a variable named after the partial. In
this case, the partial is _post, and within the _post partial, you can
refer to post to get the instance that is being rendered.
You may find detailed explanation in rails guides

Show partial from another controller or model

I have a Project that has_many tasks. The Task has a _form.html.erb file that I wanted to show on my show.html.erb file from Project.
But everytime I try this, I am getting the following error:
undefined local variable or method `task'
I am using <%= render 'tasks/form' %> to render the partial.
Also, would
<% #tasks.each do |task| %>
<%= listing.task.name %>
<% end %>
do the trick to show all listings that's associated with the current page?
It looks like you are just missing to pass the task local to the partial.
This should work:
<%= render partial: 'tasks/form', locals: { task: #task } %>

Default path to look for partial

In my app/views/conversations/index.html.erb, I am writing:
<%= render #conversations %>
hoping that it would find a partial named _conversation.html.erb inside the same directory, and use it to render each elements in #conversations. (The usual Rails way)
But I get a missing template error: Missing partial mailboxer/conversations/_conversation.
I am using a Mailboxer gem, and there were no documentations for this. I know I could render a partial explicitly by <%= render partial: 'conversation', locals: { conversations: #conversations } %>.
Yet still, I would like to know why my app is looking for a partial for #conversations in mailboxer/conversations/, not conversations/, and if there is a way to change this behavior.
More information
<% #conversations.each do |conversation| %>
<%= div_for conversation %>
<% end %>
produces HTML:
<div class="mailboxer_conversation" id="mailboxer_conversation_16"> ... </div>
<div class="mailboxer_conversation" id="mailboxer_conversation_17"> ... </div>
....
Perhaps the mailboxer_ in front of conversation has something to do with this situation also?
This happens because, in later versions of Mailboxer, models are namespaced under Mailboxer. (e.g. Mailboxer::Conversation, Mailboxer::Message.)
I commented on the GitHub issue also.
You could try providing the full path to the partial, e.g.
<%= render :partial => "yourfoldername/conversation", collection: #conversations %>

Rendering Rails partial form in another partial

I have models called project and test. A project has many tests.
In the index.html.erb of tests, I have:
<%= render #tests %>
So I therefore have a file called _test.html.erb, and in it I have:
<%= render "form" %>
I then have a filed called _form.html.erb with:
<%= form_for([#project, #project.tests.build]) do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<% end %>
But I get an exception:
undefined method `tests' for nil:NilClass
So #project is apparently nil. I understand my set up is a bit strange, so I'm not sure how I would refactor this to work?
Instance variables are accessible from any level of rendering.
You can render 100 partials inside each other and you would still have access to those same ivars.
The problem looks like you aren't actually setting #project anywhere.
You probably are looking for "test.project" in your form.
<%= render #tests, project: #project %>
Then
<%= render 'form', project: project %>
The idea is to pass in the #project instance variable as a local variable.
Are both partials in the same view?
You will also have to pass the #project object to the partial and every partial that uses #project.
Example:
<%= render #tests, project: #project %>

Resources