这让我非常头疼...
所以我有一个应用程序,它需要一个侧边栏,列出与用户播放器有关的各种信息。此侧边栏的一个部分是朋友列表。现在,当玩家 A 向玩家 B 发送好友请求时,该请求应该会自动记录在 B 的侧边栏中,我打算使用 WebSockets 来执行此操作。
这是我cp.js.coffe.erb
文件(目前只有几个 ERB 片段;会有更多加载,我宁愿先让它工作):
$ ->
$("#cp").accordion()
if `"WebSocket" in window`
socket = new WebSocket("ws://localhost:8080")
socket.onopen = =>
console.log("Connection Open")
init = {
sender: "cp"
action: "init"
user: <%= @user.id %>
token: <%= cookies["remember_token"] %>
}
socket.send(init.to_json)
socket.onerror = (e)=>
console.log(e)
socket.onclose = =>
console.log("Closed")
socket.onmessage = (m)=>
console.log("Recieved: #{m.data}")
msg = m.data.JSON.parse
switch msg.action
when "ret_init"
when "friend_udt"
refreshFriend()
refreshFriend() ->
html = "<%= j render 'layouts/friends' %>"
$('#friends').empty()
$('#friends').add(html)
从理论上讲,代码本身工作正常,问题是
app/views/layouts
render
方法(或大多数其他 ERB 方法)。事情是这样的:我不能在我的application.html.erb
文件中包含该文件,我考虑使用 AJAX 请求该文件,但据我了解,这将立即执行 Javascript 一次且仅一次,我需要其中的方法不断可用来更新侧边栏。
有没有办法包含此文件,以便它与 ERB 和 CoffeScript 一起使用,以便它能够持续用于页面?我是否误解了整个 AJAX 请求方法?
感谢@nzifnab对JS的帮助。现在我的朋友部分看起来像这样:
<ul id="friendlist">
<% if Relation.find_by(owner: @user.id, type: "freq") != nil %>
<% Relation.find_by(owner: @user.id, type: "freq").each do |r| %>
<li class="friend-request-cp"><%= link_to "/#{User.find(r.character).name}" %></li>
<% end %>
<% end %>
<% if Relation.find_by(owner: @user.id, type: "friend") != nil %>
<% Relation.find_by(owner: @user.id, type: "friend").each do |r| %>
<li class="friend-cp"><%= link_to "/#{User.find(r.character).name}" %></li>
<% end %>
<% end %>
</ul>
我需要对每个项目应用两种不同的样式,因此我在这里使用 ERB。这工作正常,因为它是在页面首次导航到时加载的,但我的代码应该在每次收到任何新交互的通知时重新呈现该部分。然后,它将再次使用数据库中的数据重新填充列表。有没有更有效的方法呢?我还能用你给我看的hamlcoffeeassets
宝石做到这一点吗?
随之而来的是轻微的切线:
顺便说一下,我在Windows 7上使用Ruby 2.0.0-p247和Rails 4。我觉得有必要包括它,因为与 Ubuntu 有很大不同的 gem 存在一些主要的兼容性问题。我不得不从 Ubuntu 迁移到 Windows,因为从 13.04 更新到 13.10 破坏了该操作系统上的所有 Ruby Gem。我不必找到修复程序:我实际上只有四天的时间来构建这个应用程序。
资产管线中使用erb
,但你必须记住,它只会渲染一次,永远,而不是每个用户渲染一次,所以即使有一个@user
变量(不会有),它永远不会改变。 您可以在咖啡文件中将erb
用于路由路径和环境变量等内容,但不能用于用户特定的配置和对 JS 的动态更改等内容。 无论如何,这是不好的做法。
真正应该做的是使用javascript库来读取cookie,而不是尝试使用rails来做(这将使你能够访问一些你似乎正在尝试做的事情)。 当你需要更多的动态行为时,你应该将数据属性或其他值渲染到 html DOM 本身中,并使用 javascript 来读取它。
看看这个饼干库:https://github.com/carhartl/jquery-cookie
还有许多其他可以通过快速的谷歌搜索查看。
socket.onopen = =>
console.log("Connection Open")
init = {
sender: "cp"
action: "init"
user: $.cookie('user_id')
token: $.cookie('remember_token')
}
有几种方法可以使用 JS 为视图呈现新标记。 一种方法是使用 js 模板。 我是这里的hamlcoffeeassets
库的忠实粉丝:https://github.com/netzpirat/haml_coffee_assets 虽然它使用 haml 作为视图,而不是 ERB。 也有ERB变体。
您可以像这样向app/assets/templates/friend.jst.hamlc
添加一些标记:
%p This is my friend markup #{@friend.name}
然后你可以像这样从你的JS渲染它:
$('#friends').append(JST['templates/friend'](friend: {name: 'Bob'}))
这会将模板中的标记附加到您传入的内插值。 在我的示例中,您最终会在#friends
容器中使用此标记:
<p>This is my friend markup Bob</p>
或者,您可以通过 rails 将您想要的部分呈现到 JSON 响应中,只是一个字符串,然后将其插入到您的文档中......
所以你的JS可能看起来像这样:
socket.onmessage = (m)=>
console.log("Recieved: #{m.data}")
msg = m.data.JSON.parse
switch msg.action
when "ret_init"
when "friend_udt"
refreshFriend(msg.friendHTML)
refreshFriend(html) ->
$('#friends').html(html)
更新
关于你的雇员再培训局问题... 首先,您的部分效率非常低,每次渲染数据库时都会对数据库进行四次类似的调用。 haml_coffee_assets
用于haml
标记语言(我更喜欢ERB),如果您想要ERB,请使用eco:https://github.com/sstephenson/eco
中渲染它,那么你需要通过通知数据响应将这个"朋友关系"数据作为JSON发送,在渲染javascript部分时,你无权访问活动记录或任何控制器方法或实例变量 - 它们不会回击服务器,它们只使用你的javascript当时可以访问的内容。
真的应该去app/assets/javascripts/cp.js.coffee.erb
,你可以在资产管道中使用erb就好了(见这里) 不过,请确保您拼写coffee
扩展名正确!
这样做,您应该能够通过ajax毫无问题地调用它,路径将是/assets/cp.js
。
试试这个宝石:"咖啡豆"
-
将您的咖啡文件命名为"some_file.html.erb"
<%= coffeescript_tag_do %> # your coffee script here ... <% end %>
-
在另一个 ERB 文件中:
<%= render file: '.../some_file' %>