Rails:在 CoffeeScript 或 JavaScript 资产文件中访问控制器实例变量
Posted
技术标签:
【中文标题】Rails:在 CoffeeScript 或 JavaScript 资产文件中访问控制器实例变量【英文标题】:Rails: access controller instance variable in CoffeeScript or JavaScript asset file 【发布时间】:2012-01-20 18:49:19 【问题描述】:在 Rails 3.1 中,无法使用 等语法访问资产 js.erb 或 coffee.erb 文件中的控制器实例变量,其中 @foo 在控制器中设置。那么问题就是将控制器变量传递给 CoffeeScript 或 javascript 资产的最佳方法是什么。
这个问题已经在论坛上以多种复杂的形式提出,但我再次询问的目的是有一个地方可以收集所有建议,并且提供的代码简单易读。另请注意,我专门指的是资产,而不是查看响应文件。
【问题讨论】:
这是 ***.com/questions/8108511/… 的副本吗?看起来那里接受的答案会有所帮助。 @Thilo 据我了解,该问题是指视图文件夹中的 .slim 模板,因此实际上 CoffeeScript 正在作为视图的一部分而不是预先作为资产文件进行处理。如果我错了,请纠正我。 是的,我对 Rails 不够熟悉,无法确定该答案是否适用。但要点似乎是将您需要的所有实例变量呈现到一段 Javascript 中,然后其他资产可以引用。 在这里会引起争议,问你为什么需要这样的访问权限? 另外,相关问题的第二个答案实际上显示了我认为更好的做法。将您需要的任何数据存储在您真正需要的数据属性中。此外,请考虑使用 JSON 响应从您的 rails 操作请求非 html 模板的任何内容。 【参考方案1】:我过去做过的几种方法
将数据放入隐藏字段,访问js/coffee中的数据
# single value
<%= hidden_field_tag "foo_name", @foo.name, :id => "foo-name" %>
$('#foo-name').val();
# when the 'value' has multiple attributes
<%= hidden_field_tag "foo", @foo.id, :id => "foo", "data-first-name" => @foo.first_name, "data-last-name" => @foo.last_name %>
$foo = $('#foo')
console.log $foo.val()
console.log $foo.data("firstName")
console.log $foo.data("lastName")
另一种选择:将数据加载到erb中的js数据结构中,从js/coffee访问它
<% content_for(:head) do %>
<script>
window.App = window.App || ;
window.App.Data = window.App.Data || ;
window.App.Data.fooList = [
<% @list.each do |foo| %>
<%= foo.to_json %>,
<% end %>
];
</script>
<% end %>
# coffee
for foo in window.App.Data.fooList
console.log "#foo.id, #foo.first_name #foo.last_name"
我不喜欢像这样从 erb 中的 ruby 构建 javascript 数据,只是感觉有些不对劲——虽然它可能很有效
另一种选择:进行 ajax 调用并按需从服务器获取数据
我也对其他想法和方法感兴趣
【讨论】:
如果您需要运行循环并构造 json,您可以使用 before_filter 运行方法来构造单个 JSON 对象并将其分配给实例变量。然后,您只需在视图的 Javascript 赋值中输出一个实例变量。我发现这比 ajax 更好,因为它减少了一个 HTTP 请求。 第二个选项看起来很不错。必须记住那个。【参考方案2】:关于这个特定主题,最近(2012 年 2 月)有一个非常好的轨道演员: #324 Passing Data to JavaScript
它显示了 3 种方式:脚本标签、数据属性和 Gon gem。 我认为房子涵盖了所有可用的技术。我只想提一下,当您拥有大量数据、动态数据或两者的组合时,最好使用 AJAX 调用。
【讨论】:
Rudolph,打开 RailsCast,它还会显示代码示例。比我能给出的更好的例子:) 我打开了,我看到了,但答案应该是包含所有相关示例代码的(即不要求您访问另一个页面才能获得相关信息) ... 这里提到的技术和在视图中传递变量给Js的技术是一样的:***.com/questions/2464966/… 这是最好的答案。我添加了一个包含使用 gon 的示例的答案,但我的编辑批准率太低,我只是将其作为答案重新发布。【参考方案3】:我没有使用隐藏字段,而是选择将数据属性添加到 jquery 可以拾取的容器 div。
<div class="searchResults" data-query="<%= @q %>"></div>
然后是 jquery 来访问它
url: "/search/get_results?search[q]=" + $(".searchResults").data("query") + "&page=" + p
我觉得这是将数据传递给 javascript 的最简洁的方式。在发现无法使用来自控制器的 rails 资产管道将变量传递给咖啡脚本文件之后。这是我现在使用的方法。不能等到有人用最好的导轨设置控制器方式。
【讨论】:
【参考方案4】:在控制器中:
@foo_attr = "data-foo-1" => 1, "data-foo-2" => 2
在视图中(HAML):
#foo@foo_attr
在 CoffeeScript 资产中:
$("#foo").data("foo-1")
$("#foo").data("foo-2")
【讨论】:
【参考方案5】:在您的 javascript 数据失控的情况下,使用 gon gem 仍然是进入 rails 的首选方式,即使在 2015 年也是如此。设置 gon 后,您可以通过简单地分配将数据传递到您的 javascript 文件将数据发送到 rails 中的 gon 对象。
(Gemfile)
gem 'gon'
(controller)
def index
gon.products = Product.all
(layouts)
<%= include_gon %>
(public/javascripts/your_js_can_be_here.js)
alert(gon.products[0]['id');
(html source automatically produced)
<script>
window.gon = ;
gon.products = ["created_at":"2015", "updated_at":"2015, "id":1, "etc":"etc"];
您可以从 Ryan Bate 的截屏视频中阅读有关 Gon 或其他两个 rails-javascript 频道的更多详细实现细节。http://railscasts.com/episodes/324-passing-data-to-javascript
【讨论】:
【参考方案6】:您可以编辑变量并将其添加到控制器中的 params 数组,然后在 response.js.erb 中访问它们。这是params[:value]
的示例:
def vote
value = params[:type] == "up" ? 1 : -1
params[:value] = value
@public_comment = PublicComment.find(params[:id])
have_voted = @public_comment.evaluators_for(:pub_votes_up) << @public_comment.evaluators_for(:pub_votes_down)
unless have_voted.include?(@current_user) # vote
@public_comment.add_or_update_evaluation(:"pub_votes_#params[:type]", value, @current_user)
else # unvote
@public_comment.delete_evaluation(:"pub_votes_#params[:type]", @current_user)
params[:value] = 0
end
respond_to do |format|
format.js # vote.js.erb
end
end
这是一个伴随 response.js.erb 的示例
button = $('<%= ".pub#params[:type]_#params[:id]" %>')
label = button.find('strong')
<% comment = PublicComment.find(params[:id]) %>
label.html('<%= comment.reputation_for(:"pub_votes_#params[:type]").to_i %>')
<% if params[:value] == 1 %>
button.addClass('btn-success')
<% elsif params[:value] == -1 %>
button.addClass('btn-danger')
<% else %>
if button.hasClass('btn-success') button.removeClass('btn-success')
if button.hasClass('btn-danger') button.removeClass('btn-danger')
<% end %>
【讨论】:
以上是关于Rails:在 CoffeeScript 或 JavaScript 资产文件中访问控制器实例变量的主要内容,如果未能解决你的问题,请参考以下文章
是否/为啥 Rails 6 仍在使用/推荐 CoffeeScript?
导轨 3.1。如何防止 Rails 使用 CoffeeScript?
Rails - 从 JavaScript 调用 CoffeeScript