簡體   English   中英

Rails 4更新實例變量而無需重新加載頁面

[英]Rails 4 update instance variables without page reload

有沒有一種方法可以在不重新加載頁面的情況下重新加載視圖中的實例變量?

我有一個AJAX帖子,它創建了一個新記錄。 我希望將該記錄添加到現有實例變量中。

所以我有一個動作(例如action ,它可以處理我在action.html.erb的視圖:

def action
  @variable = Variable.where().to_a
end

然后我有一個AJAX請求,它執行一個動作,例如action2

def action2
  @new_record = Variable.create(params)
  respond_to do |format|
    format.html
    format.json {render :json => @new_record.to_json}
  end
end

有什么方法可以刷新@variable實例變量以包括新創建的記錄嗎?

我可以提出另一個AJAX action請求嗎? 如果是這樣,我怎么會檢測AJAX請求action

我已經用request.xhr?嘗試了這個^^ request.xhr? 但是在執行JS .click()之后,它拋出了一個奇怪的StandardError

我不確定我是否朝着正確的方向前進,但是如果我朝着正確的方向走,這就是我編寫的所有代碼...

我正在構建一個即時消息服務,並且我承認我完全是一起破解一個原型。 我知道有更干凈的方法可以處理高流量負載,但是我現在正在研究原型。

視圖代碼如下所示:有:HTML聊天框,我發出AJAX請求以每2秒查找一次新消息,在相同的功能中,我向上面所說的action發出AJAX請求(實際上命名不同) ,在“刷新”功能之后,我有了一個.click()函數來更新用戶視圖(剛剛提交的用戶視圖)。

<div id="wrapper">
    <div id="menu">
        <p class="welcome">Welcome, <b></b></p>
        <p class="logout"><a id="exit" href="#">Exit Chat</a></p>
        <div style="clear:both"></div>
    </div>

    <div id="chatbox">
      <% @messages.each do |message| %>
        <% if session[:email] == message.email %>
          <!-- post to the right side -->
          <div id="right-side">
            <p>Email: <%= message.email %></p>
            <p>Message: <%= message.message %></p>
          </div>
        <% else %>
          <!-- post to the left side -->
          <div id="left-side">
            <p>Email: <%= message.email %></p>
            <p>Message: <%= message.message %></p>
          </div>
        <% end %>
      <% end %>
    </div>

    <form id="frm1" action="">
      Message: <input id="message_input" type="text" name="fname"><br>
      <!-- <input type="submit" value="Submit"> -->
      <button name="submitmsg" type="submit"  id="submitmsg">Try it</button>
    </form>
</div>

<p id="demo"></p>
<script>

  function retrieveMessages(){
    var message;
    $.ajax({
      type:"GET",
      url:"<%= get_messages_path %>",
      dataType:"json",
      data: {chat_id: <%= @message_info[:chat_id] %>,
              last_message: <%= @messages.last.created_at.to_i %>},
      success:function(data){
        if (data != null){
          console.log(data);
          console.log(data.message);
          message = data.message;
          document.getElementById("chatbox").innerHTML +=  message + '<br>';
        }
      }
    });

    $.ajax({
      type:"GET",
      url:"<%= new_message_path %>",
      dataType:"json",
      success:function(data){
        console.log("success!");
        }
      }
    });
    setTimeout(retrieveMessages, 2000);
  }

  $(document).ready(function(){
    //get messages
    setTimeout(retrieveMessages, 2000);

    //send messages
    $("#submitmsg").on('click', function(e){
      e.preventDefault();
      var x = document.getElementById("frm1"); //This is the form, and not the value of the textbox
      var text = "";
      var i;
      for (i = 0; i < x.length ;i++) {
        text += x.elements[i].value;
      }
      // document.getElementById("chatbox").innerHTML += text;
      text_with_br = text + "<br>"
      document.getElementById("chatbox").innerHTML += text_with_br;
      document.getElementById("frm1").reset();
      // console.log(document.getElementById("right"));
      //Actual message is in 'text'
      $.ajax({
        url: "/messages",
        method: "post",
        data: { message: text,
                chat_id: <%= @message_info[:chat_id] %>,
                message_counter: <%= @message_info[:message_counter] + 1 %> },
        dataType: "JSON",
        success: function(response){
          //do something,maybe notify user successfully posted their message
        },
        error: function(error){
          console.log(error);
        }
      });

    });
  });
</script>

那么對於action的動作我有(實際上是new動作,和我所謂@variable實際上是@messages

def new
  # debugger
  # Message.create(:chat_id => 5)
  if session[:email].nil?
    #user not logged in
    redirect_to new_session_path(:message => "need to login")
  else
      @user = User.where(:email => session[:email]).first
      @message_info = Hash(email: @user.email, message_counter: 0, chat_id: Message.last.chat_id + 1)
      @messages = Message.where(:chat_id => @message_info[:chat_id]).to_a

      respond_to do |format|
        format.html
        format.json
      end

  end
end

然后執行AJAX請求以獲取最新消息(以便其他瀏覽器的查看者可以查看)的操作如下...

def get
  @new_message = Message.where(["created_at > ?", Time.at(params[:last_message].to_i)]).first

  respond_to do |format|
    format.html
    # format.json {render json: @new_message}
    format.json {render :json => @new_message.to_json}
  end
end

更新

@eggroll建議的代碼如下,但我遇到了引導程序問題

在此處輸入圖片說明

從您的代碼開始,以下是我嘗試的解決方案。 我重命名了元素,希望它可以使此代碼更具自記錄性,從而使您更容易分辨我所做的事情。 它並不完美,但是可以在Chrome中為我工作,因此希望對您有所幫助。 我假設起始的chat_id為1。如果不是,則可以在控制器的get_last_chat_id方法中對其進行調整。

(注意:有幾行代碼對您來說是多余的,但是對於我來說,必須能夠在我現有的一個應用程序中運行此代碼。您還應該知道我正在使用Postgres,jQuery, Devise,HAML和Bootstrap 4 alpha。)

app / controllers / messages_controller.rb

class MessagesController < ApplicationController

  before_action :authenticate_user!
  before_action :set_current_user_email, only: [:index, :display_all_messages]
  before_action :set_current_messages,   only: [:display_all_messages]

  def index
  end


  def get_last_chat_id
    last_chat_id = Message.pluck(:chat_id).max
    if last_chat_id
      puts '*** LAST CHAT ID: ' + last_chat_id.to_s
    else
      last_chat_id = 0
      puts '*** LAST CHAT ID: ' + last_chat_id.to_s
    end

    respond_to do |format|
      format.json { render json: last_chat_id }
    end
  end


  def save_new_message
    new_message = Message.new do |msg|
      msg.email        = params[:email]
      msg.message_text = params[:message_text]
      msg.chat_id      = params[:chat_id]
    end

    puts '*** NEW MESSAGE EMAIL:   ' + new_message.email
    puts '*** NEW MESSAGE TEXT:    ' + new_message.message_text
    puts '*** NEW MESSAGE CHAT ID: ' + new_message.chat_id.to_s

    # Source: https://makandracards.com/housetrip-deck/16879-jquery-ajax-success-done-will-not-run-callbacks-if-request-is-json-but-the-response-is-empty-typical-200
    respond_to do |format|
      if new_message.save
        puts '*** NEW MESSAGE WAS SAVED!!!'
        format.json { render json: { ok: true }, status: :ok }
      else
        puts '*** NEW MESSAGE WAS NOT SAVED!!!'
        format.json { render json: { ok: false }, status: :unprocessable_entity }
      end
    end
  end


  def display_all_messages
    respond_to do |format|
      if @current_messages
        format.js  {  }
      else
        puts '*** THERE ARE NO MESSAGES TO DISPLAY!!!'
      end
    end
  end


  private

    def set_current_messages
      @current_messages = Message.by_created_desc
    end


    def set_current_user_email
      @current_user_email = current_user.email
    end


    def message_params
      params.require(:message).
        permit(:email, :message_text)
    end


end

app / models / message.rb

class Message < ActiveRecord::Base

  scope :by_created_desc, -> { order(created_at: :desc) }

end

db / migrate / 20160717000100_create_messages.rb

class CreateMessages < ActiveRecord::Migration
  def change

    create_table :messages do |t|

      t.string  :email,        null: false
      t.text    :message_text
      t.integer :chat_id,      null: false

      t.timestamps null: false

    end

    add_index :messages, :chat_id, unique: true

  end
end

app / assets / javascripts / messages.js (2016年7月17日更新)

var messagesRefresher;

$(document).ready(function(){

  // AJAX error handling, outputting error messaging to the console
  $(document).ajaxError(function (event, jqxhr, settings, thrownError) {
    console.log('EVENT: '        + JSON.stringify(event, null, '\t'));
    console.log('JQXHR: '        + JSON.stringify(jqxhr));
    console.log('SETTINGS: '     + JSON.stringify(settings, null, '\t'));
    console.log('THROWN ERROR: ' + thrownError);
  });

  messagesRefresher = setInterval(refreshMessages, 2000);

  $('#new-message-create-btn').on('click', function(e){
    e.preventDefault();
    $('#new-message-create-btn').addClass('no-display');
    $('#new-message-form-wrapper').removeClass('no-display');
  });

  $('#new-message-cancel-btn').on('click', function(e){
    e.preventDefault();
    $('#new-message-form-wrapper').addClass('no-display');
    $('#new-message-create-btn').removeClass('no-display');
  });

  $('#new-message-submit-btn').on('click', function(e){
    e.preventDefault();
    var newMessageEmail  = $('#new-message-email').val();
    var newMessageText   = $('#new-message-text').val();

    console.log('*** NEW MESSAGE EMAIL: ' + newMessageEmail);
    console.log('*** NEW MESSAGE TEXT:');
    console.log(newMessageText);

    getLastChatId('/messages/get_last_chat_id').done(function(lastChatId) {
      var newMessageChatId = lastChatId + 1;
      console.log('*** NEW MESSAGE CHAT ID: ' + newMessageChatId)

      saveNewMessage('/messages/save_new_message?email=' + newMessageEmail + '&message_text=' + newMessageText + '&chat_id=' + newMessageChatId).done(function(data) {

        console.log('*** MESSAGE # ' + newMessageChatId + ' SAVED!!!')

        $('#new-message-form-wrapper').addClass('no-display');
        document.getElementById('new-message-form').reset();
        $('#new-message-create-btn').removeClass('no-display');

        refreshMessages;
      });

    });

  });

});


function refreshMessages() {
  displayAllMessages('/messages/display_all_messages').done(function(data) {
    console.log('*** MESSAGES REFRESHED!!!');
  });
};


function getLastChatId(url) {
  return $.ajax({
    url:       url,
    type:     'get',
    dataType: 'json'
  })
  .fail(function() {
    alert('AJAX Get Last Chat Id Error');
  });
};


function saveNewMessage(url) {
  return $.ajax({
    url:       url,
    type:     'get',
    dataType: 'json'
  })
  .fail(function() {
    alert('AJAX Save New Message Error');
  });
};


function displayAllMessages(url) {
  return $.ajax({
    url:       url,
    type:     'get',
    dataType: 'script'
  })
  .fail(function() {
    alert('AJAX Display All Messages Error');
  });
};


$(window).unload(
  function(event) {
    clearInterval(messagesRefresher);
  }
);

app / views / layouts / application.html.haml(摘要) (添加:2016-07-18)

.
.
.

%head

  %meta{ charset: 'UTF-8' }
  %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1, shrink-to-fit=no' }

  -# Derived from: http://v4-alpha.getbootstrap.com/getting-started/browsers-devices/
  %meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' }

  = csrf_meta_tags

  -# For page-specific meta tags
  = content_for?(:meta_tag) ? yield(:meta_tag) : ""

  %title Chatbox

  = stylesheet_link_tag 'application'
  = yield :page_stylesheet_link_tags

  = javascript_include_tag 'application'
  = yield :page_specific_javascript

.
.
.

app / views / messages / index.html.haml

- content_for :page_specific_javascript do
  = javascript_include_tag 'messages.js'

#chatbox
  %h1 Chatbox

  = link_to 'New Message', 'javascript:;', id: 'new-message-create-btn', class: 'btn btn-sm btn-primary'

  #new-message-form-wrapper.no-display
    = form_tag messages_path, id: 'new-message-form' do
      = hidden_field_tag 'new-message-email', @current_user_email
      #new-message-form-label-wrapper
        = label_tag 'new-message-text', 'Enter Your Message:'
      #new-message-form-text-wrapper
        = text_area_tag 'new-message-text', nil, rows: 6, cols: 70
      #new-message-form-buttons-wrapper
        = submit_tag 'Post Message', id: 'new-message-submit-btn', class: 'btn btn-sm btn-success'
        = link_to 'Cancel', 'javascript:;', id: 'new-message-cancel-btn', class: 'btn btn-sm btn-secondary'


  #display-messages-wrapper

    #messages-column-left.pull-md-left
      %h3 Messages From Others
      #messages-other-users

    #messages-column-right.pull-md-right
      %h3 My Messages
      #messages-current-user

app / views / messages / display_all_messages.js.haml

$('#messages-other-users').html('');
$('#messages-current-user').html('');
- @current_messages.each do |msg|
  - if msg.email == @current_user_email
    $('#messages-current-user').append("#{ escape_javascript render(partial: 'message', locals: { email: msg.email, message_created_at: msg.created_at, message_text: msg.message_text }) }");
  - else
    $('#messages-other-users').append("#{ escape_javascript render(partial: 'message', locals: { email: msg.email, message_created_at: msg.created_at, message_text: msg.message_text }) }");

app / views / messages / _message.html.haml

.message-wrapper

  .message-attribution-wrapper
    %span.message-attribution-label Posted by:
    %span.message-attribution-text=email + ' on ' + message_created_at.strftime('%Y-%m-%d') + ' at ' + message_created_at.strftime('%I:%M:%S %p')

  .message-text-wrapper
    .message-label Message:
    .message-text= message_text

app / assets / stylesheets / messages.scss (2016年7月17日更新)

.no-display {
  display: none !important;
}

#chatbox {
  width: 90%;
  margin: .5em auto;
}

#new-message-form-wrapper {
  width: 48%;
  padding: 1em;
  border: 1px solid #ccc;
}

#new-message-form-label-wrapper > label {
  font-weight: 700;
}

#new-message-form-buttons-wrapper {
  margin-top: .5em;
}

#new-message-submit-btn {
  margin-right: .3em;
}

#new-message-submit-btn,
#new-message-cancel-btn {
  width: 8em;
}

#new-messages-form-wrapper,
#display-messages-wrapper {
  margin-top: 1.5em;
}

#messages-column-left,
#messages-column-right {
  width: 48%;
}

.message-wrapper {
  width: 96%;
  margin: 1em auto;
  padding: .5em;
  border: 1px solid #ccc;
}

.message-attribution-label,
.message-label {
  font-weight: 700;
}

config / routes.rb

Rails.application.routes.draw do

  resources :messages, only: [:index]
  get  'messages/get_last_chat_id',     to: 'messages#get_last_chat_id'
  get  'messages/save_new_message',     to: 'messages#save_new_message'
  get  'messages/display_all_messages', to: 'messages#display_all_messages'

end

assests / javascripts / application.js (添加:2016-07-18)

//= require jquery 
//= require jquery_ujs 
//= require jquery-ui 
//= require bootstrap-sprockets

config / initialization / assets / rb (添加:2016-07-18)

Rails.application.config.assets.precompile += %w( messages.js )

資產/樣式表/application.scss (添加:2016-07-18)

@import 'bootstrap_4a/bs_4a_variable_overrides'; 
@import 'bootstrap'; 
@import 'bootstrap_4a/bs_4a_customization'; 

app / assets / stylesheets / bootstrap_4a / bs_4a_variable_overrides (添加:2016-07-18)

// http://v4-alpha.getbootstrap.com/getting-started/flexbox/
// Enabling flexbox means reduced browser and device support:
//   Internet Explorer 9 and below do not support flexbox.
//   Internet Explorer 10 has a few known quirks, requires using a prefix,
//   and only supports the syntax from the old 2012 version of the spec.

$enable-flex: true;

app / assets / stylesheets / bootstrap_4a / bs_4a_customization (添加:2016-07-18)

// http://v4-alpha.getbootstrap.com/getting-started/browsers-devices/
// As of Safari v8.0, fixed-width .containers can cause Safari
// to use an unusually small font size when printing.
// One potential workaround for this is adding the following CSS:

  @media print {
    .container {
      width: auto;
    }
  }

  body {
    position: relative;
  }

Gemfile (添加:2016-07-18)

gem 'sass-rails', '~> 5.0' 
gem 'jquery-rails' 
gem 'jquery-ui-rails', '~> 5.0.5' 
gem 'autoprefixer-rails', '~> 6.3.6' 
gem 'bootstrap', '~> 4.0.0.alpha3'

更新: apps / views / messages / display_all_messages.js.haml的 .js.erb版本

$('#messages-other-users').html('');
$('#messages-current-user').html('');
<% @current_messages.each do |msg| %>
  <% if msg.email == @current_user_email %>
    $('#messages-current-user').append("<%= escape_javascript render(partial: 'message', locals: { email: msg.email, message_created_at: msg.created_at, message_text: msg.message_text }) %>");
  <% else %>
     $('#messages-other-users').append("<%= escape_javascript render(partial: 'message', locals: { email: msg.email, message_created_at: msg.created_at, message_text: msg.message_text }) %>");
  <% end %>
<% end %>

您可以使用成功回調,並將div附加到$(“#chatbox”),以下是該示例代碼。

jQuery.ajax({
    type: 'GET',
    url: loadUrl,
    data: dataString,
    dataType: 'html',
    success: function(response) {
        $("#chatbox").append("
        <div id="left-side">
        <p>Email:"+  response[:email]+"</p>
        <p>Message:"+ response[:message]+"</p>
      </div>"
    }
});    

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM