在第一次操作加载时,如何将实例变量传递给js.erb?

时间:2016-10-31 00:22:19

标签: jquery ruby-on-rails erb ruby-on-rails-5 ujs

我有ProfilesController,其中包含以下内容:

if @profile.ratings
  @rating = @profile.ratings.find_by(user: current_user)
end

当页面刚刚加载时,在它甚至向控制器发回请求之前,为了respond_to,我想访问@rating中的app/assets/javascripts/profiles.js.erb实例变量像这样的文件:

console.log('<%= @rating %>');

现在只返回nil

如何在第一次加载时访问该@rating中的profile.js.erb个实例变量?

修改1

为了一些清晰度和更多背景,这就是正在发生的事情。

我有一些JS驱动的UISliders看起来像这样:

enter image description here

生成此内容的HTML(以及更像它) - Profile#Show.html.erb

        <td>
            <p>
              <button type="button" class="btn btn-danger m-r-sm slider-step-value" id="slider-step-value-speed-<%= @profile.slug %>">5</button>
              Speed
            </p>
            <div id="slider-speed" class="slider"></div>
        </td>
        <td>
            <p>
              <button type="button" class="btn btn-primary m-r-sm slider-step-value" id="slider-step-value-tackling-<%= @profile.slug %>">3</button>
              Tackling
            </p>
            <div id="slider-tackling" class="slider"></div>
        </td>

这是JS - app/assets/javascripts/profiles.js.erb - 对应于HTML:

  var sliders = $('.slider');
  var buttons = $('.slider-step-value');

  for ( var i = 0; i < sliders.length; i++ ) {
    var button = $(sliders[i]).prev('p').find('button')[0];
    var _slider_type = sliders[i].id.split('-')[1];
    console.log(_slider_type);
    console.log('<%= @rating %>');
    noUiSlider.create(sliders[i], {
      start: 5,
      step: 1,
      behaviour: 'tap',
      connect: [true, false],
      range: {
        'min':  1,
        'max':  10
      }
    });

    attachEvent(sliders[i], button);
  }

  function attachEvent(slider,button){
    slider.noUiSlider.on('update', function( values, handle ) {
      button.innerText = parseInt(values[handle]);
      var _profile_id = button.id.split('-').slice(4).join('-');
      var _rating_type = button.id.split('-')[3]
      var url = "/profiles/" + _profile_id + "/" + _rating_type + "_rating/?" + _rating_type + "=" + button.innerText

      $.ajax({
        type: "PATCH",
        url: url,
        success: function(){
          // console.log(_profile_id + "'s " + _rating_type + " was successfully updated.");
        },
        error: function(){
          // console.log(_profile_id + "'s " + _rating_type + " was NOT successfully updated.");
        }
      })
    });
  }

这是我的ProfilesController#Show行动:

class ProfilesController < ApplicationController
  before_action :set_profile, only: [:show, :edit, :update, :destroy, :invite_user, :speed_rating, :tackling_rating, :dribbling_rating, :passing_rating]
  authorize_resource except: [:dashboard, :speed_rating, :dribbling_rating, :tackling_rating, :passing_rating]
  skip_authorization_check only: [:dashboard, :speed_rating, :dribbling_rating, :tackling_rating, :passing_rating]

def show
    if @profile.ratings
      @rating = @profile.ratings.find_by(user: current_user)
    end
end
end

所以问题是在第一次加载时,HTML会加载HTML中硬编码的默认值(我最终会将其更改为正常的db值,这很简单)。然后在加载JS之后,这个noUiSlider脚本会同时更新button标记(也就是彩色框)的值和滑块的位置。

它的方式是在这一行:

noUiSlider.create(sliders[i], {
          start: 5,

因此,我希望它从我的5控制器中提取@rating,而不是仅仅默认为Profiles#Show,这类似于start: <%= @rating %>。这将自动更新Slider&amp; button(又名彩盒)就像我想要的那样。

问题出在第一页加载,@rating为空/空。这就是我正在努力的目标。

也许我需要发送get请求,但我不确定如何处理此问题。

修改2

对于记录,AJAX调用工作并像我期望的那样更新数据库。当我移动滑块时,会发生这种情况。所以问题是只在第一页加载,我需要滑块&amp;如果button中有值,则需要更新@rating

3 个答案:

答案 0 :(得分:1)

我明白了。

基本上,我这样做的最佳方法是在初始加载时从数据库中提取的每个data标记中添加button属性。

因此,虽然我的旧button标记看起来像这样:

<button type="button" class="btn btn-danger m-r-sm slider-step-value" id="slider-step-value-speed-<%= @profile.slug %>">5</button>

我的新button标记如下所示:

<button type="button" class="btn btn-danger m-r-sm slider-step-value" id="slider-step-value-speed-<%= @profile.slug %>" data-speed-value="<%= speed_rating %>"><%= speed_rating %></button>

speed_rating是我profiles_helper.rb中定义的辅助方法,如下所示:

  def speed_rating
    if @rating.speed
      @rating.speed
    else
      "5"
    end
  end

然后,在我的JS中,我所做的就是为每个按钮选择data属性,如下所示:

var button = $(sliders[i]).prev('p').find('button')[0];
var _slider_type = sliders[i].id.split('-')[1];
var _original_value = $('button#' + button.id).data(_slider_type + "-value");

唯一新的一行就是:

var _original_value = $('button#' + button.id).data(_slider_type + "-value");

然后我将其添加到我的noUiSlider.create电话中,现在它看起来像这样:

noUiSlider.create(sliders[i], {
  start: _original_value,

相反它最初看起来像这样:

noUiSlider.create(sliders[i], {
   start: 5,

瞧......就像魔法一样!

答案 1 :(得分:0)

你的问题对我来说没有多大意义,因为你说你正在尝试渲染@rating,但是你编写了代码来渲染'&lt;%= @ profile.ratings%&gt;' 。此外,您共享的if语句表明有时该字段为零。我会看到我能做什么,但我认为你需要发布更多信息。

我想你有这样一个页面:

<%# profile.html.erb %>
<div id="profiles">
  ...
  <button data-remote="true" >Load ratings</button>
</div>

然后当您单击此按钮时,它会向您的控制器发送一个请求:js format,它会加载您的profile.js.erb。

必须是显示任何文字的控制器操作。如果您正在从rails查看HTML页面,则会在某处执行某些控制器操作。您需要将@rating实例变量添加到该控制器操作,并在相应的视图中呈现它。

你能发帖:

  1. 您正在访问的路径(网址)
  2. 呈现的路由控制器
  3. 呈现该路线的视图(如果有)

答案 2 :(得分:0)

如果您需要从profiles.js.erb访问该变量,请将其计算结果放入相应控制器的profiles操作中。目前,它是在另一个行动中计算出来的,当然,profiles中没有。