26

Possible Duplicate:
Rails: confused about syntax for passing locals to partials

I want to pass local variable(which doesn't have relevant field in model) to partial.

# infos/index.html.erb

<%= render :partial => 'info', :locals => {:info => first, :img_style => "original"} %> 

:img_style will be html style for image.

# infos/_info.html.erb
<% first = @infos.shift %>
<%= image_tag(info.image.url, :class => img_style),  info %> 
# and here goes code for normal iteration
<% @infos.each do |e| %>
# etc

But it does not work, it returns error:

# GET /infos/
undefined local variable or method `img_style' for #<#<Class:0xc471f34>:0xc470cc4>

It can be done without making redundant partials?

Sorry for my English. :P

EDIT:

Well model Info don't have :img_style field

# db/schema.rb
  create_table "infos", :force => true do |t|
    t.string   "title"
    t.text     "description"
    t.integer  "place_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "image_file_name"
    t.string   "image_content_type"
    t.integer  "image_file_size"
    t.datetime "image_updated_at"
    t.text     "short"
  end

EDIT2:

Even simple

<%= img_style %>

don't works.

Application Stack Trace

app/views/infos/_info.html.erb:3:in `_app_views_infos__info_html_erb___1029249744_92158380_1472718'
app/views/infos/index.html.erb:7:in `_app_views_infos_index_html_erb__184644561_92172050_0'
app/controllers/infos_controller.rb:8:in `index'

EDIT3:

Views

# infos/index.html.erb
<div >
  <h1><%= t('info.infos') %></h1>
  <div id="left">
    <% first = @infos.shift %>
    <div>
      <% @aimg_style = "original"%>
      <%= render 'info', :locals => {@img_style => @aimg_style } %>
    </div>
    <ul>
      <% @infos.each do |e| %>
        <li>
          <div>
            <%= render :partial => 'info', :object => e %>
          </div>
        </li>
      <% end %>
    </ul>
    <%= will_paginate @infos %>

# infos/_info.html.erb
<%#= link_to thumbnail(info, "listTabsImg", false, img_style), info %>
  <%#= image_tag(info.image.url()) %>
  <%= img_style %>
<p>
  <strong class="nameBox"><%= link_to info.title, info %></strong>
  <span><%= info.short %>...</span>
  <%= link_to "#{t('more')} »", info %>
</p>

FINALLY

This don't works:

# infos/index.html.erb
<% first = @infos.shift %>
<div class="boxEvent">
  <% @aimg_style = "original"%>
  <%= first %>
  <%= render 'info', :locals => {:info => first, :img_style => @aimg_style } %>
</div>

This works:

# infos/index.html.erb
  <% @infos.each do |e| %>
    <li>
      <div class="boxEvent">
        <%= render :partial => 'info', :locals => {:info => e, :img_style => "original"} %>
      </div>
    </li>
  <% end %>

Anybody know why?

Community
  • 1
  • 1
nothing-special-here
  • 11,230
  • 13
  • 64
  • 94
  • Which line of code is in which file? Is the `<%= image_tag` placed in the `_info` partial, or somewhere else? Does the error raise when the partial is called by your first example or you call it from some other place? I ask because you mentioned redundant partials, but you haven't said you call the partial from more than one place. – Arsen7 Jun 08 '11 at 14:09
  • This may be nothing--since your question already includes the right code--but using the shorthand syntax will cause this failure: `render 'info', :locals => { ... }`. If you are calling the partial explicitly, `render :partial => 'info', :locals => { ... }`, then I don't see any reason why this isn't working. As @Arsen7 suggested, it would be helpful to know how your partials are nested in your template. – neezer Jun 08 '11 at 14:23
  • @Arsen7 Error is raised when i /infos from browser. I wanted to do that without redunant partials(each partial for each style, for example: _info_small.html.erb, _info_original.html.erb etc) – nothing-special-here Jun 08 '11 at 15:03
  • Your model dosnt need a img_style field. You are defining it when you call the partial. – Devin M Jun 08 '11 at 15:08
  • If the question now is 'why?' then I would say it's a bug in Rails. But usually in programming it is good to be as concrete as possible. The _guessing_ and _magic_ usually leads to frustration. If I want to render a partial, then I should say it explicitly. In this case obeying that rule would save you by accident ;) – Arsen7 Jun 09 '11 at 08:30
  • Answer why does it works like that: http://stackoverflow.com/questions/4402556/rails-confused-about-syntax-for-passing-locals-to-partials – nothing-special-here Jun 09 '11 at 09:18

5 Answers5

50

I actually just use this syntax in Rails 3:

render "a_partial", :a_local_variable => whatever, :another_variable => another
d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • 7
    Well.. this syntax also don't work `undefined local variable or method 'img_style' for #<#:0xb474978>` – nothing-special-here Jun 08 '11 at 14:56
  • 1
    It should work just fine. The variable must be being accessed from within some other scope. – d11wtq Jun 08 '11 at 15:02
  • If it still doesn't work for you - probably your partial is cached. To check that add any garbage (for example a line 'lalala') at the beginning of your partial and check if this time the value is passed to the partial. – Alexander Jan 28 '14 at 18:15
12

This should work:

<%= render :partial => "info", :locals => { :img_style => "original" } %>

With this partial:

# infos/_info.html.erb
<%= image_tag(info.image.url, :class => img_style),  info %>

However if you are calling the partial wrong then try this as the partial:

# infos/_info.html.erb
<%= image_tag(info.image.url(img_style)),  info %>
Devin M
  • 9,636
  • 2
  • 33
  • 46
5

I've spent several hours on this; in a view, render :partial => ? , :locals => (....} it seems if you first call:

render :partial => ? without a locals hash

and THEN call render :partial => ? with a locals hash the locals hash IS NOT passed to the view.

If the first call includes a locals hash with the same variables set to '' then the second call with REAL values will work.

mind.blank
  • 4,820
  • 3
  • 22
  • 49
John
  • 51
  • 1
  • 1
  • 3
    It is not a bug, it is a feature. :) – nothing-special-here Mar 01 '12 at 09:03
  • It sounds like you're saying a first call to `render` can break a subsequent call to `render`. I've never experienced this behavior. Could you elaborate or clarify? Thank you. – Nathan Sep 11 '12 at 00:47
  • This is indeed a very simple "feature". If you have a `partial` that asks for `foo`, then calling `render partial` without passing a value for `foo` will result in an undefined variable error. So the code breaks not in the place where you pass the variable, but in the place you *don't pass it*. By the way, if you *really* want to have an 'optional' local, guard it with `defined?` in the partial, like this: `foo if defined? foo`. – Leonid Shevtsov Feb 09 '15 at 18:02
2

Your code (the one you have shown in the first line) should work. There is no error. I have even tested it myself and it works for me.

The usual reasons for such errors are:

  • misspelled variable name
  • calling the partial also from some other place, where you do not pass a :local.

The fact that your model does not have the attribute "img_style" is not important.

I can see that in your infos/index.html.erb you have two places where you call render :partial => 'info', :object => ... and you do not have :locals here. Just the line numbers do not match with the stacktrace you have posted earlier, so it's hard to say which call causes the problem.

I guess both calls to the render method need corrections.

In the first one, be specific, and call render :partial => "info" instead of render "info". This may be a bug in Rails, but for some strange reason, :locals seem to not be passed to the view in this case.

In the second call to render just add the :locals.

Arsen7
  • 12,522
  • 2
  • 43
  • 60
1

I believe the problem is the trailing , info call. It is looking in the info object for img_style. You don't need it.

I love using partials but recently have seen the beauty in helper methods too, especially in simple renderings like this one.

def info_image(info, class_name="original")
   image_tag(info.image.url, :class => class_name)
end

then just

<%= info_image(first) %>

or

<%= info_image(first, "anotherclass") %>

in the view. Much cleaner.

If ever it becomes more complex. You'll only have to change code in one place.

natedavisolds
  • 4,305
  • 1
  • 20
  • 25