12/08/2018, 15:22

Asynchronous communication with ajax. Flow of processing explanation

We will be doing asynchronous communication using ajax and post messages without screen transition. I did not understand the process flow of ajax and jbuilder very well and I had a lot of trouble in understanding, so i make this post for not to forget Because I did not understand the process ...

We will be doing asynchronous communication using ajax and post messages without screen transition. I did not understand the process flow of ajax and jbuilder very well and I had a lot of trouble in understanding, so i make this post for not to forget

Because I did not understand the process flow of ajax and jbuilder well, it took a long time to write the code. ※ If i made something wrong, please leave comment below!

1. Send form

  • _form.html.haml
= form_for [@group, @message], html: {class: 'msg_form'} do |f|
  = f.hidden_field :user_id, value: "#{@message.user_id}"
  = f.text_field :body, autofocus: true, placeholder: "type a message", class: "form__textfield"
  = link_to "#" do
    %i{class:"fa fa-picture-o"}
  = f.submit "Submit", class: "form__submit"
  • Routing
GET    /groups/:group_id/messages(.:format) messages#index
POST   /groups/:group_id/messages(.:format) messages#create

2. Stop form transmission event and go to js processing

$(function() {
// Omitted
  $('.msg_form').on('submit', function(e) {
    e.preventDefault();
    // Here stops the submit event of the form

    var api_url = window.location.pathname; 
    // Get the path while sending the request by ajax

    var formdata = new FormData($(this).get(0)); 
    // Get value entered in form as formdata object
    // You can check the contents of formdata with the following code
    // for(item of formdata) console.log(item);


    // Using ajax, send a request in json format.
    $.ajax({
      url: api_url,       // Request path. Here is '/ groups / 23 / messages'
      type: 'POST',       // HTTP method
      data: formdata,     // Send with request data
      contentType: false, // This is the type of data included in the request ( It seems to be in the request header) 
      processData: false, // This means not to change the actual type of data included in the request
          // It seems that the above two designations have to be done
                                      // Reference : http://semooh.jp/jquery/api/ajax/jQuery.ajax/options/
      dataType: 'json',   //send a request in JSON format
    })
    // So far, Specification of ajax request.
    // As the request is sent, the routing is read.

    // (Following is omitted)
    // The code indicates If its going well do this, if not do that
  });
});

3. Controller Process

A request for '/groups/:group_id/messages(.:format)' was sent from ajax at 2 and HTTP method 'POST'. According to routing messages # create (in short, the create action of the messages controller is processed.)

  • messages_controller.rb
class MessagesController < ApplicationController
  def create
    @message = Message.new(message_params) // generate Message instant
    @message.user_id = current_user.id  // Add user_id, group_id which can not be taken with params
    @message.group = Group.find(params[:group_id]) // Associate Group with Message instance
    if @message.save // If you can save the Message instance
      respond_to do |format| 
        format.html {redirect_to group_messages_path(params[:group_id])} 
        // Redirect if request is in HTML format
        // Although it should not be read by this application but i still write down here

        format.json
        // If the request is in JSON format, run jbuilder (for this time)
        // In this application, format.json should be read.
      end
    else // If you can not save Message instant
      flash[:notice] = "Please input the message"
      redirect_to group_messages_path(params[:group_id])
    end
  end

  private
  def message_params
    params.require(:message).permit(:body ,:image, :user_id).merge(group_id: params[:group_id])
  end
end

4. jbuilder work flow

The request was read in JSON format by ajax, and the create action in messages_controller.rb worked. Respond_to follows the description of format.json, views/messages/create.json.jbuilder is read.

  • create.json.jbuilder
json.name @message.user.name
json.body @message.body
json.image @message.image
json.group_id @message.group_id
json.user_id @message.group_id
json.time @message.created_at

About the json style data object sent by the request @message.user.name is value for the name key. For the body key @message.body

In short, the contents of data is a hash of the JSON format as follows. By specifying .key, each value can be acquired.

Object {name: "yukihiro", body: "ooo", image: null, group_id: 23, user_id: 23…} Since jbuilder processing is over, we go to the second half of ajax in message.js.

5. When the ajax request succeeds / fails

$(function() {
  function new_message(message) {
    var new_message = $('<div class="msg">' +
                '<p class="msg__username">'+ message.name +'</p>' +
                '<p class="msg__time">'+ message.time + '<p>' +
                '<p class ="msg__passage">' + message.body +'</p>' +
                '</div>');
    return new_message;
  }

  $('.msg_form').on('submit', function(e) {
    // Omitted
    // I sent a request with this ajax just now
    $.ajax({
      url: api_url,
      type: 'POST',
      data: formdata,
      contentType: false,
      processData: false,
      dataType: 'json',
    })

    // When ajax request is successful .done is read
    .done(function(message){ 
      console.log('success!'); // For debugging
      console.log(message); // For debugging
      var html = new_message(message); // This is added because of adding a message asynchronously
      $('.msg').append(html); // Add to reality
      // Add 'html' to the end of 'chat__content'
      $('.form__textfield').val(');   //Empty text field
      $('.form__submit').prop('disabled', false);  //Activate the submit button
    })

    // If ajax request fails, .fail will be read
    .fail(function(message){
      console.log('error!');
    });
0