chrisfin
chrisfin

Reputation: 21

Render partial with refreshed data via AJAX

I am pretty new to JS, but I hope I am missing something simple. I am trying to reload a partial that displays an image asynchronously. When a user clicks on the link below, it registers their vote, then (it should) render the pins partial with a new image from the database.

index.html.erb (The link)

<%= link_to 'Less', {:controller => "pins", 
                     :action => "create_view", 
                     :rank => 0,
                     :user_id => current_user.id, 
                     :pin_id => @pins.id
                     },
                     :method => "post", :remote => true %>

pins_controller.rb (Method called by link)

def create_view
  @view = View.new
  @view.user_id = params[:user_id]
  @view.pin_id = params[:pin_id]
  @view.rank = params[:rank]

  if @view.save
   respond_to do |format|
    format.html { redirect_to root_path }
    format.js
   end
  else
   render action: "new"
  end
end

pins_controller.rb (Method that generates @pins)

def index
  seen = Array.new
  max_pins = 20
  sex = current_user.sex
  views = View.user_views(current_user)
  seen = views.map(&:pin_id)
  @pins = Pin.new_pin(seen, sex)

models/pins.rb

def self.new_pin(pin_ids, sex)
  b = TRUE
  self.find(:first, :conditions => ["sex = ? AND active = ? AND id not in (?)", sex, b,    pin_ids], :order => "created_at desc" )
end

index.html.erb (The DIV and partial)

<div id="main_well">
     <%= render @pins %>
</div>

create_views.js.erb (The javascript triggered on click)

$('#main_well').html("<%= escape_javascript(render (partial: "pin", :locals => { pin: @pins})) %>");

_pin.html.erb (The partial to be reloaded by JS)

<div class="row">
 <div class="center_well">
   <div class="well" style="background-image: url('<%= pin.image %>')" onclick="window.open('<%= pin.product_url %>','mywindow');"></div>
 </div>
</div>

I have been at this for a while. Here's what I know. Clicking the link does remotely update the database. And if I change the JS to $('#main_well').remove(), clicking the link does remove the image asynchronously. However, I cannot for the life of my get the image to update onclick without refreshing the page. Thanks in advance for your help.

EDIT

As in the answer below, the instance variable @pins was not leading in the create_views method. Thus, regenerating the instance variable link this seemed to solve the problem.

pins_controller.rb

def create
 seen = Array.new
 max_pins = 20
 sex = current_user.sex
 views = View.user_views(current_user)
 seen = views.map(&:pin_id)
 @pins = Pin.new_pin(seen, sex)

 @view = View.new
 @view.user_id = params[:user_id]
 @view.pin_id = params[:pin_id]
 @view.rank = params[:rank]

 if @view.save
  respond_to do |format|
     format.html { redirect_to root_path }
     format.js
  end
 else
  render action: "new"
 end
end

However, this solution only serves to reload the partial successfully once. If I click the link, it reloads the image. However, if I click the link again, nothing happens. However, if I change the function like so it works perfectly:

pins_controller.rb

def create
 seen = Array.new
 max_pins = 20
 offset = rand(Pin.count)
 @pins = Pin.first(:offset => offset)

 @view = View.new
 @view.user_id = params[:user_id]
 @view.pin_id = params[:pin_id]
 @view.rank = params[:rank]

 if @view.save
  respond_to do |format|
     format.html { redirect_to root_path }
     format.js
  end
 else
  render action: "new"
 end
end

It seems that the local variable "view" is not being reloaded the second time I click the link. I have no idea why. Any help would be greatly appreciated.

views.rb

def self.user_views(user)
  self.find(:all, :conditions => ['user_id = ?', user])
end

Upvotes: 2

Views: 325

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

Update

In reference to the comments, this worked:

def index
  seen = Array.new
  max_pins = 20
  sex = current_user.sex
  views = View.user_views(current_user)
  seen = views.map(&:pin_id)
  @pins = Pin.new_pin(seen, sex)
end

def create
  seen = Array.new
  max_pins = 20
  sex = current_user.sex
  views = View.user_views(current_user)
  seen = views.map(&:pin_id)
  @pins = Pin.new_pin(seen, sex)

  @view = View.new
  @view.user_id = params[:user_id]
  @view.pin_id = params[:pin_id]
  @view.rank = params[:rank]

  if @view.save
     respond_to do |format|
         format.html { redirect_to root_path }
         format.js
     end
  else
     render action: "new"
  end
end

Original Answer

From looking at your code, it seems it should work, but I imagine there are syntax problems preventing it from doing so


@pins

You're calling @pins in a completely new action

The problem is that your ajax request is a new request (your instance is concluded after the initial HTTP request ends). This means your @pins instance variable is not persisting through the ajax call, and is likely why your partial won't render correctly

Try:

#app/controllers/pins_controller.rb
def index
    @pins = Pin.new_pin(seen, sex)
end

def create
    @pins = Pin.find(params[:id])
end

Partial

When calling your partial, you can then try this:

$('#main_well').html("<%=j render partial: "pin", :locals => { pin: @pins} %>");

This should work if your @pins variable is called properly


Update

def self.user_views(user)
   where(user_id: user.id)
end

Upvotes: 1

Mike S
Mike S

Reputation: 11429

Try changing this:

$('#main_well').html("<%= escape_javascript(render (partial: "pin", :locals => { pin: @pins})) %>");

to this (add html_safe to the end of the escape_javascript call):

$('#main_well').html("<%= escape_javascript(render :partial => 'pin', :locals => { pin: @pins}).html_safe %>");

EDIT

The problem is probably related to how the partial is being rendered. Does this work?

$('#main_well').html("<%= escape_javascript("#{image_tag pin.image}").html_safe %>")

Upvotes: 0

Related Questions