JQuery Send Ajax Request With ‘delete’ Method (Two Approaches)

Knowledge point:

$.post( url [, data ] [, success ] [, dataType ] ) is a shorthand Ajax function, which is equivalent to:
$.ajax({
type: ‘POST’,
url: url,
data: data,
success: success,
dataType: dataType
});

Two approaches:

1. a form with a hidden field ‘_method’ set to ‘delete’ and use JQuery $.post method:

1.1 form code:

<form action=”test url” accept-charset=”UTF-8″ method=”post” class=”form_example”>
  <input type=”hidden” name=”_method” value=”delete” />
  <label for=”Please_enter_the_username_that_you_want_to_delete:”>Please enter the username that you want to delete:   </label>
  <input type=”text” name=”name” id=”name” />
  <input type=”submit” name=”commit” value=”Send delete request” />
</form>

1.2 JQuery code:

$(‘.form_example’).submit(function(e) {
  var $this = $(this);
  var form = $this;
  var data = form.serialize();

  // Prevent form form submit normally
  e.preventDefault();

  // Use ajax to submit the form
  $.post(form.attr(‘action’), data).done(function(data) {
  // If ajax request succeed, code goes here
  });
});

2. a form without ‘_method’ hidden field and use JQuery $.ajax method with ‘type’ set to ‘delete’:

2.1 form code:

<form action=”test url” accept-charset=”UTF-8″ method=”post” class=”form_example”>
  <label for=”Please_enter_the_username_that_you_want_to_delete:”>Please enter the username that you want to delete:  </label> 
  <input type=”text” name=”name” id=”name” /> 
  <input type=”submit” name=”commit” value=”Send delete request” />
</form>

2.2 JQuery code:

$(‘.form_example’).submit(function(e) {
  var $this = $(this);
  var form = $this;
  var data = form.serialize();

  // Prevent form form submit normally
  e.preventDefault();

  // Use ajax to submit the form
  $.ajax({
    type: ‘delete’,
    url: url,
    data: data,
    success: success,
    dataType: dataType
  });
});

Advertisements

Rails Submit Form Using ‘delete’ Method Explanation

Sometimes we need to submit form using methods other than ‘post’, in this example, it’s ‘delete’.

For example, I wanted to delete a user when a form is submitted with the user name and ‘delete’ method.

1. I created the route like this:

delete ‘test url’, to: ‘users#destroy’

So I will handle the delete function in users controller, destroy action.

 

2. The view code:

<%= form_tag(‘test url’, method: :delete) do %>
  <%= label_tag ‘Please enter the username that you want to delete:’ %>
  <%= text_field_tag :name %>
  <%= submit_tag ‘Send delete request’ %>
<% end %>

 

2. This view code generates the following html code:

<form action=”test url” accept-charset=”UTF-8″ method=”post”>
  <input name=”utf8″ type=”hidden” value=”✓” />
  <input type=”hidden” name=”_method” value=”delete” />
  <input type=”hidden” name=”authenticity_token” value=”5Rj1osaYdsOkH94pyig99l5Ud64U1H25LCuK33plQuf2Lg+a/+Ub6VVlYBSOvDotOIrX3SCKB6mYsfZTyPkI+Q==” />
  <label for=”Please_enter_the_username_that_you_want_to_delete:”>Please enter the username that you want to delete:</label>
  <input type=”text” name=”name” id=”name” />
  <input type=”submit” name=”commit” value=”Send delete request” />
</form>

As you can see above, the form method is still ‘post’. I was really confused at this point, since the method didn’t turn out to be the ‘delete’ method I expected.

But actually rails generated a hidden input called _method that is supposed to carry the intended verb for the server to interpret. In this case, it’s ‘delete’, exactly what I need.

 

3. Let’s see the view, it looks like this:

view

I typed ‘test user name’ and hit ‘Send delete request’ button, it sent out this http request:

delete request

The request method is ‘Post’, with form data ‘_method’ set as ‘delete’ which sent my request to users controller, destroy action. Job done.

Rails Marshal Example

1. Why use Marshal?

Basically anytime you want to store a whole object in byte stream and need to retrieve the object from the byte stream later.

This is the situation I encountered and also why I decided to write this blog:

1.1  I had an object that logically should be stored in session, but it was a relatively big object, so I need to store it in the database.

1.2  Since the attributes of this object could change, which meant I couldn’t create each database column based on the attribute names and types.

For example, see the user_obj below, it now has ‘name, age, address, weight, height’ attributes, but it might have more attributes or the type of the attributes could change.

1.3 So I decided to store the object as a serialized object in one column of the database.

 

2. The following is a simple example:

2.1 Use the following Database migration file to create a User table with user_id, user_info, created_at and updated_at fields.

db/migrate/20150625130210_create_user.rb:

class CreateUser < ActiveRecord::Migration
  def change
    create_table :user do |t|
      t.integer :user_id
      t.binary:user_info

      t.timestamps null: false

    end
  end
end

Reminder: user_info needs to be type ‘binary‘. I tried ‘text’, it worked but it caused my system to beep.

2.2 We have a class like this:

class UserInfo
  attr_reader :name, :age, :address, :weight, :height

  def initialize(name, age, address, weight, height) 
    @name = name
    @age = age
    @address = address
    @weigtht = weight
    @height = height
  end
end

So we can create an obejct like this:

user_obj = UserInfo.new(‘christy’,  22,  ‘1021 penn circle’,  ’50’,  ‘160’)

2.3 Now we want to store this object as a serialized object in the user_info field in User table.

2.3.1  Create the serialized object:

user_serialized_obj = Marshal.dump(user_obj)

2.3.2 Save the object to database:

User.create(user_id: 1, user_info: user_serialized_obj)

2.4 Later, if we want to retrieve this object. we can do like this:

2.4.1 Retrieve the serialized object from database:

user_serialized_obj = User.find(1).user_info

2.4.2 Deserialize this object:

user_obj = Marshal.load(user_serialized_obj)

 

3. Marshal official reference:

http://ruby-doc.org/core-2.1.5/Marshal.html

Rails Minitest Style Guide

In the test,  should use ‘describe’,  ‘context’, ‘it’ structure.

Here I use a controller test as an example.

I have this my_controller.rb with two controller actions:

class MyController < ApplicationController
  def controller_action_1
  # Code goes here
  end

  def controller_action_2
  # Code goes here
  end
end

And controller test file my_controller_test.rb:

require ‘test_helper’

class MyControllerTest < ActionController::TestCase
# Initialize the variables that will be used in all describe block tests within MyControllerTest class
before do
v_block = ‘this variable is only accessible in this block’
@v_describe_level = ‘this varible is accessible in all describe blocks’
end

# Test for controller action 1
describe ‘#controller_action_1’ do
# Intialize the variables that will be used in all context block tests within this describe block
before do
v_block = ‘this variable is only accessible in this block’
@v_context_level = ‘this varible is accessible in all context blocks’
end

context ‘when the user is admin’ do
# Intialize the variables that will be used in all it block tests within this context block
before do
v_block = ‘this variable is only accessible in this block’
@v_it_level = ‘this varible is accessible in all it blocks’
end

it ‘must has admin role’ do
# Code goes here. Examples: http://ruby-doc.org/stdlib-1.9.3/libdoc/minitest/spec/rdoc/MiniTest/Expectations.html
# must_be
# must_be_empty
# must_be_nil
# must_be_same_as
# must_equal
# must_raise
# wont_be
# wont_be_nil
# wont_equal
# wont_include
end

it ‘must redirect to admin management page’ do
# Code goes here, example:
# assert_redirected_to
end
end

context ‘when the user is not admin’ do
it ‘must not have admin role’ do
end

it ‘must redirect to non-admin management page’ do
end
end
end

describe ‘#controller_action_2’ do
# Code goes here
end

private

# Helper functions goes here
end

 

Ruby – Dry Code with Map, Next and Reject

For example, we have this Channel class:

class Channel
  attr_reader :id, :name

  def initialize(id, name) 
    @id = id
    @name = name
  end
end

 

1.

What we have:

One list of objects:

current_channels = [Channel.new(1, ‘channel1’), Channel.new(2, ‘channel2’), Channel.new(3, ‘channel3’)]

Task: Get arrays of ids from this list.

1.1 Bad solution

current_channel_ids = []

current_channels.each do |channel|
  current_channel_ids << channel.id
end

1.2 Better solution using map

current_channel_ids = current_channels.map { |channel| channel.id }

1.3 Best solution using map

current_channel_ids = current_channels.map(&:id)

 

2.

What we have:

Two lists of objects:

current_channels = [Channel.new(1, ‘channel1’), Channel.new(2, ‘channel2’), Channel.new(3, ‘channel3’)]

need_to_be_assigned_channels = [ Channel.new(1, ‘channel1’), Channel.new(4, ‘channel4’)]

Task: Assign channels in need_to_be_assigned_channels to current_channels array and make sure there’re no two channels with identical id.

Solution:

Before each solution, get the an array of ids from current_channels:

current_channel_ids = current_channels.map(&:id)

2.1 Bad solution

need_to_be_assigned_channels.each do |channel|
  unless current_channel_ids.include?(channel.id)
    current_channels << channel
  end
end

2.2 Better solution using next

need_to_be_assigned_channels.each do |channel|
  next if current_channel_ids.include?(channel.id)
  current_channels << channel
end

2.3 Best solution using reject

current_channels.concat(need_to_be_assigned_channels.reject { |assigned_channel| current_channel_ids.include?(assigned_channel.id) })

 

3.

What we have:

Two lists of objects:

current_channels = [Channel.new(1, ‘channel1’), Channel.new(2, ‘channel2’), Channel.new(3, ‘channel3’)]

need_to_be_deleted_channels = [ Channel.new(1, ‘channel1’), Channel.new(3, ‘channel3’)]

Task: Delete channels from current_channels if the id matches one of the ids in  need_to_be_deleted_channels.

Solution:

Before each solution, get the an array of ids from current_channels:

current_channel_ids = current_channels.map(&:id)

3.1 Bad solution

current_channels.each do |channel|
  next unless need_to_be_deleted_channel_ids.include?(channel.id)
  current_channels.delete(channel)
end

3.2 Best solution using delete_if

current_channels.delete_if { |channel| need_to_be_deleted_channel_ids.include?(channel.id) }