Rails + JS + Ajax request

Rails + JS + Ajax request

本文关键字:request Ajax JS Rails      更新时间:2023-09-26

嗨,我正在制作简单的游戏克隆,其中沃尔多(沃利(与Rails + JS + Ajax。这个想法是:玩家变成3个图像,并且必须检查3个角色(沃尔多,威尔玛,巫师(的位置。3.图像显示字段以提交名称,提交后显示高分列表。

到目前为止,我已经为时间(带有setInterval的JS变量(,点(JS + AJAX + rails控制器(编写了机制,但我无法为提交名称,点和时间建模的动作编码。

我的视图文件:

<%= form_tag('/check/highscore',  method: :post, format: :js, remote: true ) do %> 
    <%= text_field_tag 'name', 'enter your name' %>
    <%= submit_tag 'submit' %>
  <% end %>
<script type="text/javascript">
 $.ajax({
 url: "<%= highscore_check_index_path %>",
 type: "POST",
 format: "js",
 dataType: "script",
 data: { username: $(this).username, score: guessd, time: time  }, 
 success: function(data) {
 $('send_highscore').append('data.username')    
 window.waldo.HS()
},
});
};

我的控制器文件:

def highscore
 @username = params[:name] 
 respond_to do |format|
  format.js { render :layout => false } 
  format.html
 end
end
def highscore2
 record = Highscore.new 
 record.username = params[:username]
 record.score = params[:score] 
 record.time = params[:time]
 record.save 
end 

我的高分.js.erb

console.log("<%=j @username %>");
window.waldo.HS = function(username) {
 $.ajax({
  url: "<%= highscore2_check_index_path %>",
  type: "POST",
  format: "js",
  data: { username: name, score: guessd, time: time  }, 
  success: function(data) {
  console.log(data);
 $('send_highscore').append('data.username')    
}
});
});

我知道,我的 oode 质量很差,但我现在试着学习它。问题是 highscore.js.erb 没有执行,尽管我在 firebug 中看到它呈现为 js 脚本文件。highscore.js.erb的想法是混合Ruby和js变量,一起发送在检查控制器中执行highscore2操作并保存到db。

js.erb是一种糟糕的学习方式。

Ruby on Rails可以通过使用remote: true和返回JS.erb响应来用作一种穷人的单页体系结构。但它真正做到的只是给你足够的绳子来吊死自己。

这是学习 ajax 的一种非常糟糕的方法,因为它会导致糟糕的代码组织和非常非 RESTful 的应用程序,因为它导致专注于过程而不是资源。

相反,我鼓励你尝试在不混合ERB和JS的情况下学习ajax。混合服务器端和客户端逻辑只会使一切变得更加复杂,因为您必须跟踪在哪里发生的事情。

相反,您可能希望专注于在app/assets/javascripts中设置可重用的javascript函数,并获取JSON数据而不是javascript过程。

这不仅会教你用Rails做ajax,还会教你如何使用外部API来做,并教你关于如何构建和组织代码的宝贵经验。

因此,让我们开始研究如何重构:

高分应该是一种资源。

让我们从设置路由开始:

resources :highscores, only: [:create, :index, :show]

控制器:

class HighscoresController < ApplicationController
  respond_to :json, :html
  def create
    @highscore = Highscore.create(highscore_params)
    respond_with @highscore
  end
  def index
    @highscores = Highscore.order(score: :desc).all
    respond_with @highscores
  end
  def show
    @highscore = Highscore.find(params[:id])
    respond_with @highscore
  end
  private
    def highscore_params
      params.require(:highscore).permit(:username, :time, :score)
    end
end
响应

器是一个非常了不起的工具,这样我们就不必在返回响应时做一堆样板代码。我们的 create 方法如果成功,将返回200 OK,如果失败,将返回422 BAD ENTITY或其他一些"错误"的响应代码。

一些JavaScript脚手架

让我们设置一点脚手架,以便我们可以将 javascript 连接到特定的控制器和操作,而无需使用内联脚本标签。

打开layouts/application.html.erb并替换<body>标记:

<%= content_tag :body, data: { action: action_name, controller: controller_name } do %>
  <%= yield %>
<% end %>

然后将这一小块添加到applicaiton.js

// Triggers events based on the current controller and action.
// Example:
// given the controller UsersController and the action index
// users:loaded
// users.index:loaded
$(document).on('page:change', function(){
  var data = $('body').data();
  $(this).trigger(data.controller + ":loaded")
         .trigger(data.controller + "." + data.action + ":loaded");
});

你们都在谈论的那个阿贾克斯在哪里?

假设我们有一个高分列表,我们希望定期(轮询(或在用户提交高分时更新

// app/assets/javascripts/highscores.js
function getHighscores(){
  var $self = $('.highscores-list');
  return $.getJSON('/highscores').done(function(highscores){
    var elements = $.map(highscores, function(h){
      return $('<li>').text([h.username, h.score].join(', '));
    });
    $self.empty().append(elements);
  });
};
$(document).on('games:loaded highscores:loaded', function(){
  // refresh highscores every 5 seconds
  (function refresh(){
    getHighscores().done(function(){
      window.setTimeout(refresh, 5000);
    });
  }());
});

最后一部分有点毛茸茸 - 它是一个递归函数,在 ajax 调用完成时设置一个新的计时器。我们使用它而不是setInterval的原因是setInterval不在乎上一个调用是否已完成。

创建高分。

首先,让我们列出一个表单:

<%# app/views/highscores/_form.html.erb %>
<%= form_for(local_assigns[:highscore] || Highscore.new), class: 'highscore-form' do |f| %>
  <div class="field">
    <%= f.label :username %>
    <%= f.text_field :username %>
  </div>
  <%= f.hidden_field :score %>
  <%= f.hidden_field :time %>
  <%= f.submit %>
<% end %>

然后让我们用一些 ajax 的优点来补充它:

$(document).on('games:loaded highscores:loaded', function(){
  $('#new_highscore').submit(function(e){
    $.ajax(this.action, {
      data: {
        highscore: {
          username: this.elements["highscore[username]"].value,
          time: this.elements["highscore[time]"].value,
          score: this.elements["highscore[score]"].value
        }
      },
      method: 'POST',
      dataType: 'JSON'
    }).done(function(data, status, jqXHR){
      getHighscores();
      // todo notify user
    });
    return false; // prevent form from being submitted normally
  });
});