1

I'm trying to build a really simple page, where I need to generate some dynamic JavaScript for a photo gallery. Something intuitively simple, but which I'm struggling with greatly. In my controller I am building a list of Photo as @photos, then need to iterate out some JavaScript for each photo in my photo.js.erb file.

However, whenever I reach my .js.erb file, the @photos variable becomes nil... what am I missing?

controllers/photos_controller.rb file:

class PhotosController < ApplicationController
  layout "application_photos"
  def category
    @photos = ...(generates collection of Photos)...
  end
end

views/photos/category.html.haml file:

= content_for :head do
  // @photos is still initialized at this point
  = javascript_include_tag "photos"

// This partial only loads some more markup, it's inconsequential.
= render :partial => 'default_slideshow'

javascripts/photos.js.erb file:

jQuery(function($){
    // Throws NilClass error
    <% puts 'Photos: ' + @photos %>
});

I know this question has been asked a dozen times, but none of the previously accepted answers actually worked for me. Any suggestions are greatly appreciated.

8
  • 4
    remember this: asset files don't have access to instance variables declared in a controller. Commented Mar 4, 2013 at 12:25
  • Ok, good to know. How would I work around this? Commented Mar 4, 2013 at 12:30
  • Can't you just build your category.html.haml view and then jQueryize what's on the page? do you really need to access @photos from the JS? If you really need to, then you'll probably have to render the .js.erb as a view from the controller. Commented Mar 4, 2013 at 12:31
  • Mike is right. what are you planning to do with @photos? Commented Mar 4, 2013 at 12:34
  • 1
    Two more details: 1. I'm leveraging a jQuery plugin where I need to generate some JS inside that jQuery function to initialize it, 2. I wanted to put the JS in its own file for 'neatntess' and because HAML sucks to print content into directly, especially nested JS. (however, if that isn't an option, I'll bend.) Commented Mar 4, 2013 at 12:35

1 Answer 1

3

You need to send js request to the server in order to have access to the instance variable. Something like this

$(function($){
  $.ajax({
    type: "get",
    url: "..."
    })  

});

In views/photos/category.js.erb file:

alert("<%= j @photos %>")

Or you can do the same using gon gem.

app/views/layouts/application.html.erb

<head>
 <title>some title</title>
 <%= include_gon %>
 <!-- include your action js code -->
 ...

You put something like this in the action of your controller:

@your_int = 123
@your_array = [1,2]
@your_hash = {'a' => 1, 'b' => 2}
gon.your_int = @your_int
gon.your_other_int = 345 + gon.your_int
gon.your_array = @your_array
gon.your_array << gon.your_int
gon.your_hash = @your_hash

gon.all_variables # > {:your_int => 123, :your_other_int => 468, :your_array => [1, 2, 123], :your_hash => {'a' => 1, 'b' => 2}}
gon.your_array # > [1, 2, 123]

gon.clear # gon.all_variables now is {}

Access the varaibles from your JavaScript file:

alert(gon.your_int)
alert(gon.your_other_int)
alert(gon.your_array)
alert(gon.your_hash)

Hope this helps

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

3 Comments

I like the strategy, but the implementation still isn't working quite yet. I'm hung up on the controller which isn't rendering the category.js.erb file for the corresponding category view, despite having a respond_to do |format| format.js end in category's controller function. Instead I'm getting back empty HTML and "Processing by PhotosController#category as HTML" from the console.
This is injected into the head, the call which is routed to my category view thats supposed to return JS, but instead returns a 406: Not Acceptable. <script type="text/javascript"> $(function($){ $.ajax({ type: "get", url: "/photos_js/category/urban" })}); </script>. This is the same error I was getting calling the route directly, so it isn't a problem with the AJAX.
So trying to accomplish this with vanilla Rails (wiring up views just to serve JS) is a huge pain... managed to accomplish what I needed to do using gon. Marking this as accepted.

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.