12/08/2018, 18:03

Tùy biến params trong rails với định dang JSON

Tình huống gặp phải Mình có dùng rails 5.2.0 để tạo một ứng dụng check pull request trên Github sử dụng Github App. Ý tưởng là sau khi tạo pull request, người tạo sẽ comment chữ "ready" sau đó webhook của github sẽ bắn dữ liệu (payload) về sự kiện tạo comment này về server của mình để xử lý ...

Tình huống gặp phải

Mình có dùng rails 5.2.0 để tạo một ứng dụng check pull request trên Github sử dụng Github App. Ý tưởng là sau khi tạo pull request, người tạo sẽ comment chữ "ready" sau đó webhook của github sẽ bắn dữ liệu (payload) về sự kiện tạo comment này về server của mình để xử lý (bắn thông báo TO lên chatwork cho gửi tạo và các trainer). Mọi thứ ngon lành , Github gửi về payload là dự liệu dạng JSON chứa một lượng dữ liệu khá lớn, rails tự parse ra và đẩy vào params (một Hash to và dài =)) )

Hook URL của mình: https://dieuqua.net/hooks

route đến: POST HooksController#create

Payload mà github gửi tới server của mình:

{
  "action": "created",
  "repository": {
   ...vân vân
   },
   ...và mây mây
}

Rails parsing param thành:

{
  "controller": "hooks", # <= tên controller mà routes mapping đến
  "action": "create", # <= tên action trong controller, thôi nó đè lên action của payload rồi 
  "repository": { # payload đã được parse và đưa vào params
    ...vân vân
  },
  ...và mây mây
  "hooks": { # <= playload rails đã wrap với tên thuộc tính là "hooks"
    "action": "created",
    "repository": {
     ...vân vân
    },
    ...và mây mây
  }
}

Nhưng gặp phải một số vấn đề sau (như mình đã comment trong ví dụ):

  • Payload được đưa vào params nhưng bị rails đè mất action (phần quan trọng nhất của payload) (chan)
  • May quá còn cái payload tự động được wrap trong element có tên là tên controller, có cả action đây rồi (ngon)
  • Có cái phần vân vân và mây mây kia nó còn rất to, lại bị lặp nữa (deso)

Để dễ xử lý, mình muốn biến params có dạng như sau:

{
  "controller": "hooks", 
  "action": "create",
  "payload": { # <= đưa toàn bộ cái pyload github gửi tới vào element là "payload"
    "action": "created",
    "repository": {
     ...vân vân
    },
    ...và mây mây
  }
}

Giải quyết

Vô hiệu hóa "wrap_parameters"

Rails tự động wrap parameter với dữ liệu gửi lên server là đinh dạng JSON http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html

Để vô hiệu hóa đối với toàn bộ rails app chỉ cần tìm file:

# config/initializers/wrap_parameters.rb
ActiveSupport.on_load(:action_controller) do
  wrap_parameters format: [] # => và xóa bỏ :json 
end

Đối với một controller, ví dụ UsersController

class UsersController < ApplicationController
  wrap_parameters format: [] # => đặt  format là mảng rỗng
end

Tùy chỉnh việc rails parsing param đối với đinh dạng JSON

Đối với rails version > 5.0.0, ta cần chỉ cần tạo một tệp với nội dung như sau: http://api.rubyonrails.org/classes/ActionDispatch/Http/Parameters/ClassMethods.html

# Tạo tệp tin: config/initializers/json_parameter_payload.rb
ActionDispatch::Request.parameter_parsers[:json] = ->(raw_post){
  data = ActiveSupport::JSON.decode raw_post
  data.is_a?(Hash) ? {payload: data} : {_json: data} # => mình tùy chỉnh một chút chỗ này, đẩy em nó vô payload
}

Xong

(xoadi) thế là mình đã có dữ liệu như mong muốn và tiếp tục build app. Trên đây là mình chia sẻ cách tùy chỉnh lại việc parsing parameter của rails qua tình huống mình gặp phải. Nếu các bạn có cách khác hãy đóng góp cho mình qua bình luận bên dưới nhé. Cảm ơn bạn đã đọc bài viết này!

0