将Rails变量从控制器传递给JS

时间:2012-11-16 19:39:09

标签: ruby-on-rails

问题描述:

我有一组链接的视图:

<% @feeds.each do |f| %>                
  <div class="feed">
    <span class="feed_counts"> <%= f.display_counts %> </span>
    <%= link_to "refresh", { :controller => 'Feeds', :action => "refresh_feed", :feed_id => f.id}, :remote => true, :class => 'refresh_feed_link' %>
    </div>
<% end %>

用户点击链接并启动下一个控制器方法:

def refresh_feed
  @feed = Feed.find(params[:feed_id])
  @feed.parse
end

现在我想将相应span-element的内容更改为@ feed.total_count值。

我的尝试:

嗯,我知道有两种方法可以不重新加载整个页面:

方式1:

我可以在布局中包含js:

<%= render :partial => 'shared/partial_js' %>

并在partial_js中使用此代码:

<script type="text/javascript">
  $().ready(function() {

    $('.refresh_feed_link').bind('click', function() {
      $(this).closest('.feed').find('span.feed_counts').text('woo');
    });
 });
</script>

在这种情况下,我有'$(this)',我可以找到相应的'span'元素。但我没有任何可能获得我的@feed变量值。

方式2:

我可以添加

respond_to do | format |  
  format.js {render :layout => false}  
end

到我的控制器并创建refresh_feed.js.erb文件。在这个JS文件中,我可以将我的变量用作&lt;%@ feed.total_count%&gt;,但我不知道我的多个链接中的哪一个被点击了。换句话说,这个文件中的$(this)变量将是(窗口),我找不到相应的span-element。

问题:

有没有办法得到我想要的东西?
提前谢谢。

1 个答案:

答案 0 :(得分:1)

有很多方法可以做到这一点。使用您描述的方式,这里是“点击了哪个链接”问题的简单解决方案:dom_id

1)制作部分:app / views / feeds / _feed.html.erb

<%= div_for feed do %>
  <span class="feed_counts"> <%= feed.display_counts %> </span>
  <%= link_to "refresh", { :controller => 'Feeds', :action => "refresh_feed", :feed_id => feed.id}, :remote => true, :class => 'refresh_feed_link' %>
<% end %>

2)在你看来:

<%= render @feeds %>

3)在refresh_feed.js.erb文件中:

$('<%= dom_id(@feed) %>').replaceWith('<%= escape_javascript( render @feed ) %>');

还有另外一种我个人喜欢的方式,但是我需要花一点时间才能写出来,所以当我写另一种方式的时候,我会把它留在这里。


第二种方式

以下是我使用CoffeeScript和HAML的方法,因为它们更容易输入。你可以把它转换成普通的JS和ERB,它的工作方式也一样。

我会设置我的路线:

resources :feeds do
  get "refresh_feed", :on => :member

假设你有“饲料”部分,app/views/feeds/_feed.html.haml

= div_for feed, :class => 'feed_widget' do
  %span.feed_counts= f.display_counts
  = link_to "Refresh", refresh_feed_path(f), :class => 'refresh_link'

在任何视图中:

= render @feeds

// or, more explicit:

= render :partial => 'feed/feeds', :collection => @feeds, :as => :feed

现在,在app/assets/javascripts/feeds.js.coffee

# Global Scope for CoffeesScript, ignore for JS
root = exports ? this

# Check page if there are feed widgets on it and initialize a handler for each one.
jQuery ->
  if $('div.feed_widget').length
    $('div.feed_widget').each ->
      new FeedWidget $(this)

root.FeedWidget = (container) ->
  @container = container
  @refresh_link = @container.find('a.refresh_link')
  @feed_counts = @container.find('span.feed_counts')
  this.initialize()

root.FeedWidget.prototype =
  initialize: ->
    self = this
    @feed_counts.click (event) ->
      event.preventDefault()
      $.ajax
        type: 'GET'
        url: self.refresh_link.attr 'href'
        dataType: 'json'
        error: (xhr, status, error) ->
          console.log error
          console.log xhr
        success: (data, status, xhr) ->
          self.feed_counts.text data.feed_counts

然后在你的控制器中:

def refresh_feed
  @feed = Feed.find(params[:id]) #assuming you have a resourceful route to this.
  @feed.parse
  respond_to do |format|
    format.js { render :json => { feed_counts: @feed.counts }, :status => :ok } # use whatever method gets you the feed count here.
  end
end

现在您获得的JSON响应只是提要计数,并且您有一个JS侦听器/处理程序窗口小部件,它将自动显示(和函数)并将您呈现为部分。好吧?

请注意,由于我没有您的应用,因此上述代码未经过测试,因此您必须根据自己的需要对其进行优化。但提出问题,我会尽力回答。

祝你好运!