2

I'm running Rails 6.0.3.2 and I want to render a partial passing a local variable to another controller view:

My routes:

Rails.application.routes.draw do
  devise_for :users

  root to: 'notebooks#index'

  resources :notebooks, only: [:index, :new, :show, :create, :edit, :update, :destroy] do 
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
    collection do
      get "list"
    end
  end

  resources :tags

end

Notebook Model:

class Notebook < ApplicationRecord

  has_one_attached :photo
  validates :asin, presence: true, uniqueness: true
  after_initialize :init
  
  acts_as_list column: :position, add_new_at: :bottom

  has_many :taggings
  has_many :tags, through: :taggings

  def init
    self.edited ||= false
  end

end

Tag Model

class Tag < ApplicationRecord
  has_many :taggings
  has_many :notebooks, through: :taggings
end

In Tag controller:

  def index
    @tags = Tag.all.order(created_at: :asc)
  end

I tried to follow this guide and render the "index view" from Tags Controller on the "list view". The application finds the tags/_index.html file, but return the error undefined method `each' for nil:NilClass. Bellow my views code:

In app/views/notebooks/list.html.erb:

  <%= render :partial => "tags/index" , locals: {tags: @tags}%>

In app/views/tags/_index.html.erb

<% tags.each do |tag| %>
  <div>
    <div class="d-flex">
      <p><%= tag.id %></p>
      <p><%= tag.name %></p>
    </div>
    <p>tag.taggings.count</p>
  </div>
<% end %>

Anyone can point me what i'm doing wrong? I read the Layouts and Rendering in Rails documentation, but i don't have a clue why the instructions won't work on my project...

Thanks in advance!

2 Answers 2

2

The rails way to do this is just to create a partial for a single record:

# app/views/tags/_tag.html.erb
<div>
  <div class="d-flex">
    <p><%= tag.id %></p>
    <p><%= tag.name %></p>
  </div>
  <p>tag.taggings.count</p>
</div>

You can then pass the collection to render and Rails will look up the partial and render it for each member in the collection:

<%= render @tags %>

This is short for:

<%= render partial: 'tag', collection: @tags %>

See Rendering Collections.

Sign up to request clarification or add additional context in comments.

4 Comments

Of course you also need to ensure that @tags is not nil. The error is probably due to slop - the code is in the wrong controller or you've fallen victim to the common misconception that render will call the method on the other controller.
Also note that the place to populate @tags in @Yuri's case is in NotebooksController#list, not in TagsController. The question seems to imply a misunderstanding that TagsController#index is somehow tightly coupled and gets called when the partial is rendered in the notebooks view.
@rmlockerd yeah that was the common misconception is was hinting at. Render just renders views.
@max Thanks guys! I misconcepted this... I thought that the best practice was to not populate too much one controller, so I was using these two controllers (thinking that render could call a method from another controller). (Sorry for the late response, I was traveling and couldn't acess my computer)
0

I had the same problem where a local wasn't showing up in the partial. Here's my code:

<%= render "chats/messages", locals: { chat: @chat } %>

but it needed to be:

<%= render partial: "chats/messages", locals: { chat: @chat } %>

Then it worked as expected (the chat local variable was available in the partial).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.