5

I have a page that renders a collection roughly like this:

index.html.haml

= render partial: 'cars_list', as: :this_car,  collection: @cars

_cars_list.html.haml

Edit: _cars_list has other info about the individual car.

%h3 Look at these Cars!
%ul
  %li Something about this car
  %li car.description
%div
  = render partial: 'calendars/calendar_stuff', locals: {car: this_car}

_calendar_stuff.html.haml

- if car.date == @date
  %div 
    = car.date

_cars_contoller.rb

def index
  @cars = Car.all
  @date = params[:date] ? Date.parse(params[:date]) : Date.today
end

What happens in the calendar stuff partial is that this_car is always the first car in the cars collection, i.e. the same date gets printed over and over.

If I move the logic in _calendar_stuff into the cars_list partial, then the printed result changes as expected.

So it seems that Rails is not passing the local this_car object into the nested partial each time it renders the partial.

Does anyone know why?

P.S. If I structure the code with

@cars.each do |car|
  render 'cars_list', locals: {this_car: car}
end

I get the same behavior.

bknoles
  • 632
  • 7
  • 16

1 Answers1

-1

Try this refactoring and see if you get your desired output:

index.html.haml

= render 'cars_list', collection: @cars, date: @date

Get rid of the partial keyword, and pass in the @date instance variable as a local variable to encapsulate the logic in your partials. This point I got from Rails Best Practices.

_cars_list.html.haml

%h3 Look at these Cars!
%ul
  %li Something about this car
%div
  = render 'calendars/calendar_stuff', car: car, date: date

As you passed in @cars as a collection, this partial will have a reference to a singularized local variable called car, which can then be passed on to the next partial, along with the now-local date variable. Since the partial being rendered is in a different location to here (over under calendars/), the partial keyword is explicitly needed here.

_calendar_stuff.html.haml

- if car.date == date
  %div 
    = car.date

Edit

Suggested to move the call to collection to _cars_list.html.haml, but that wasn't appropriate for the problem.

Edit 2

This is the version of the above code if you still wanted to specify the local variable as this_car, so you would be overriding the car local variable that collection would have generated automatically.

index.html.haml

= render 'cars_list', collection: @cars, as: :this_car, date: @date

_cars_list.html.haml

%h3 Look at these Cars!
%ul
  %li Something about this car
  %li this_car.description
%div
  = render 'calendars/calendar_stuff', this_car: this_car, date: date

_calendar_stuff.html.haml

- if this_car.date == date
  %div 
    = this_car.date
Paul Fioravanti
  • 16,423
  • 7
  • 71
  • 122
  • Tried it, but still have the same behavior. A couple things: 1) the `partial:` is necessary in the `index.html.haml` file because i am using the collection: parameter also. i believe you can only leave it off with something like `= render 'cars_list'`. 2) The singularized local variable car works great in the `cars_list.html.haml` file, but when i pass that into `_calendar_stuff` it always passes in the first `car` in the collection, not the current car in the iterator. – bknoles Dec 20 '12 at 17:00
  • I've used `collection` without the `partial` keyword before, but if you're finding issues arise if you leave it out, by all means continue to use it. – Paul Fioravanti Dec 20 '12 at 22:34
  • I don't think that will work, as i want to render some code in `_cars_list` for each individual car and then render the `_calendar_stuff` for that same individual car. I believe rendering `calendar_stuff` with a collection will render that partial one after the other for each item in the collection – bknoles Dec 20 '12 at 23:15
  • Okay, fair enough, then the call to `collection` was originally in the right place. I might just remove that edit from my answer due to that. I can't think then why only the first object in the list would be rendered unless `@cars` only contains one car. I've got code very similar in one of my apps and rendering a partial-within-a-partial on a member object has worked without issue. – Paul Fioravanti Dec 20 '12 at 23:26
  • i'm an idiot. The rails code was working perfectly, i had a js bug in the front end that made it appear that only the first item of the collection was being passed in. thanks for your help, i'm going to just delete the question. – bknoles Dec 24 '12 at 16:53
  • You probably don't need to go so far as to delete the question. Lesson learned for anyone with the same issue is to double-check that their JavaScript code isn't interfering with anything. – Paul Fioravanti Dec 24 '12 at 22:35
  • @PaulFioravanti -- Your examples need to use 'locals' if you are using 'partial' -- see http://stackoverflow.com/a/5255921/704936 – Michael Wasser Aug 04 '15 at 19:48