我如何 POST json 数据从 android 应用程序到 Rails 服务器上的 Ruby

How can I POST json data from android app to Ruby on Rails server

我正在尝试将 json 数据发送到我的 RoR 服务器,以便在服务器收到 POST 请求时创建一个新对象。我是 RoR 的新手,所以我不确定如何正确设置它。

我一直在这里搜索其他 posts 有一段时间应用类似问题的解决方案,但我所做的似乎没有任何效果。

最后 Rails - 我专门为此设置了一条路线。

在routes.rb

post '/api' => 'expenses#post_json_expense'

在expenses_controller.rb

# For creating an expense from the android app
def post_json_expense
  Expense.new(expense_params)
end

# Never trust parameters from the scary internet, only allow the white list through.
def expense_params
  params.require(:expense).permit(:user_id, :amount, :category, :description)
end

我还关闭了令牌身份验证,以防出现问题。

在config/application

config.action_controller.allow_forgery_protection = false

在 android 方面,我正在使用 Volley 发送 POST 请求

private void saveExpense () {
        // Build the URL
        String url = "https://my-project-url.herokuapp.com/api";
        Log.i("API_REQUEST", url);

        EditText etAmount = findViewById(R.id.et_amount);
        EditText etDescription = findViewById(R.id.et_description);
        EditText etCategory = findViewById(R.id.et_category);

        // Get values from the EditTexts
        double amount = Double.parseDouble(etAmount.getText().toString());
        String description = etDescription.getText().toString().trim();
        String category = etCategory.getText().toString().trim();

        // If something was entered into all of the fields
        if (amount > 0 && !description.isEmpty() && !category.isEmpty()) {


            // Convert field entries into a JSON object
            JSONObject expenseData = new JSONObject();
            JSONObject expenseObject = new JSONObject();
            try {
                expenseData.put("user_id", user_id);
                expenseData.put("amount", amount);
                expenseData.put("description", description);
                expenseData.put("category", category);
                expenseObject.put("expense", expenseData);


            JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.PUT, url, expenseObject, new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Toast.makeText(EditExpenseActivity.this, "POST Successful", Toast.LENGTH_SHORT).show();
                    Intent intent = new Intent(EditExpenseActivity.this, MainActivity.class);
                    startActivity(intent);
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Toast.makeText(EditExpenseActivity.this, "POST Unsuccessful", Toast.LENGTH_SHORT).show();
                }
            }) {
                @Override
                public Map<String, String> getHeaders() throws AuthFailureError {
                    Map<String, String> params = new HashMap<String, String>();
                    params.put("Content-Type", "application/json");
                    return params;
                }
            };

            // Make the API request
            RequestQueue queue = Volley.newRequestQueue(this);
            queue.add(jsonObjectRequest);


        }
    }

每次尝试向应用程序 post 发送数据时,我都会收到错误响应。 我哪里错了?我对 rails 很陌生,这是我第一次尝试构建 API,所以我不确定自己做错了什么。

欢迎来到S.O.!

所以,这里有一些事情需要解决。对于初学者,在您的控制器中:

# For creating an expense from the android app
def post_json_expense
  Expense.new(expense_params)
end

所以,首先,这里调用Expense.new只会新建一个object,不会持久化到数据库;您还需要致电 save 来执行此操作。

接下来,您不会向调用方返回任何类型的响应。也许返回像新费用的 id 这样的东西是合适的,或者是费用本身。我建议像这样构造调用:

# For creating an expense from the android app
def post_json_expense
  expense = Expense.new(expense_params)
  unless expense.save
    # TODO: Return an error status with some useful details
    # You can get some from expense.errors
    return render status: 400, json: { error: true }
  end
  # Render a JSON representation of the expense on successful save
  render json: expense.as_json
end

接下来,在客户端,你发送Content-typeheaders,这很好,但你也可以发送Acceptheaders,这会提示服务器端关于您希望收到什么:

public Map<String, String> getHeaders() throws AuthFailureError {
  Map<String, String> params = new HashMap<String, String>();
  params.put("Content-Type", "application/json");
  params.put("Accept", "application/json");
  return params;
}

最后,您已将方法分配给服务器上的 POST 路由:

post '/api' => 'expenses#post_json_expense'

但是您在您的应用中将其作为 PUT 调用:

JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.PUT, url, expenseObject, new Response.Listener<JSONObject>() {

因此,URL 处没有 PUT 路由,因此请求总是失败。

解决这些问题应该会让您获得成功的响应。

就个人而言,我发现使用像 curl 这样的简单实用程序通常有助于调试此类通信错误,当您不知道问题是 app-side 编码问题还是server-side 编码问题(或两者都有)。您可以通过使用诸如 curl 之类的东西来消除变量,您可以确信它是有效的,然后从那里进行调试。

希望这对您有所帮助!