Rails 3, passing local variable to partial [duplicate]
Asked Answered
O

5

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?

Obannon answered 8/6, 2011 at 13:42 Comment(6)
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.Piscina
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 @Piscina suggested, it would be helpful to know how your partials are nested in your template.Cammycamomile
@Piscina 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)Obannon
Your model dosnt need a img_style field. You are defining it when you call the partial.Amortizement
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 ;)Piscina
Answer why does it works like that: #4403056Obannon
M
50

I actually just use this syntax in Rails 3:

render "a_partial", :a_local_variable => whatever, :another_variable => another
Molt answered 8/6, 2011 at 14:29 Comment(3)
Well.. this syntax also don't work undefined local variable or method 'img_style' for #<#<Class:0xb477984>:0xb474978>Obannon
It should work just fine. The variable must be being accessed from within some other scope.Molt
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.Doloritas
A
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 %>
Amortizement answered 8/6, 2011 at 15:8 Comment(0)
P
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.

Ploch answered 1/3, 2012 at 3:12 Comment(3)
It is not a bug, it is a feature. :)Obannon
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.Sesquicentennial
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.Coin
P
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.

Piscina answered 8/6, 2011 at 15:12 Comment(0)
H
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.

Henghold answered 8/6, 2011 at 15:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.