weixin_33721427 2016-02-14 11:52 采纳率: 0%
浏览 48

Rails + JS + Ajax请求

Hi I'm making simple clone of game where is Waldo (Wally) with Rails + JS + Ajax. The idea is: player becomes 3 images and has to check where 3 characters (Waldo,Wilma,Wizard) are. After 3. image shows up field to submit name and after submit show high score list.

So far, i have code the mechanism for time (JS variable with setInterval), points (JS + AJAX + rails controller) but i can't code the action for submit name, points and time to model.

My view file:

<%= 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()
},
});
};

my controller file:

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 

my highscore.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')    
}
});
});

I know, my oode is very bad quality, but i try to learn it now. Problem is that the highscore.js.erb is not executed although i see it in firebug rendered as a js script file. The idea of highscore.js.erb is to mix ruby and js variables and together sent do highscore2 action in check controller and save to db.

  • 写回答

1条回答 默认 最新

  • weixin_33744141 2016-02-14 16:58
    关注

    js.erb is a bad way to learn.

    Ruby on Rails can be used as a kind of poor mans Single Page Architecture by using remote: true and returning JS.erb responses. But all it really does it gives you enough rope to hang yourself.

    Its a really bad way to learn ajax as it leads to poor code organisation and a very non RESTful application as it leads to a focus on procedures instead of resources.

    I instead encourage you to try to learn ajax without mixing ERB and JS. Mixing server side and client side logic just makes everything much more complicated as you have to keep track of what is happening where.

    Instead you might want to focus on setting up reusable javascript functions in app/assets/javascripts and fetching JSON data instead of javascript procedures.

    This will teach you not only to do ajax in Rails but also how to do it with external API's and teach you valuable lessons about how to structure and organise code.

    So lets start looking at how to refactor:

    Highscores should be a resource.

    Lets start by setting up the routes:

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

    And the controller:

    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
    

    Responders is a pretty awesome tool that makes it so that we don't have to do a bunch of boilerplate code when it comes to returning responses. Our create method will return 200 OK if it was successful and 422 BAD ENTITY or some other "bad" response code if it failed.

    Some javascript scaffolding

    Lets set up a little bit of scaffolding so that we can hook our javascript up to a specific controller and action without using inline script tags.

    Open up layouts/application.html.erb and replace the <body> tag:

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

    Then add this little piece to 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");
    });
    

    Where is that ajax y'all was talkin' bout?

    Lets say we have a list of highscores that we want to update either at regular intervals (polling) or when the user submits a highscore.

    // 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);
        });
      }());
    });
    

    That last part is a bit hairy - its a recursive function that sets a new timer when the ajax call has completed. The reason we use this and not setInterval is that setInterval does not care if the previous call was completed or not.

    Creating Highscores.

    First lets russle up a form:

    <%# 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 %>
    

    And then lets spiff it up with some ajax goodness:

    $(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
      });
    });
    
    评论

报告相同问题?

悬赏问题

  • ¥15 宇视监控服务器无法登录
  • ¥15 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
  • ¥50 STM32单片机传感器读取错误
  • ¥50 power BI 从Mysql服务器导入数据,但连接进去后显示表无数据
  • ¥15 (关键词-阻抗匹配,HFSS,RFID标签天线)