Как я могу отправить данные JSON из приложения Android на сервер Ruby on Rails - PullRequest
0 голосов
/ 22 апреля 2019

Я пытаюсь отправить данные json на мой сервер RoR, чтобы новый объект создавался при получении сервером запроса POST.Я действительно новичок в RoR, поэтому я не уверен, как правильно это настроить.

Я некоторое время искал другие сообщения здесь, применяя решения для подобных проблем, но ничего, что я делаю, похоже, не работает.

На конце Rails - у меня есть маршрут, настроенный специально для этой цели.

в маршрутах.*

Я также отключил аутентификацию токена в случае, если это вызывает проблему.

в 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);


        }
    }

Я получаю сообщение об ошибке каждый раз, когда пытаюсь опубликовать данные в приложении.Куда я иду не так?Я довольно новичок в rails, я впервые пытаюсь создать API, поэтому я не уверен, что делаю неправильно.

1 Ответ

0 голосов
/ 22 апреля 2019

Добро пожаловать в S.O.!

Итак, есть несколько вещей, которые необходимо рассмотреть здесь. Для начала, в вашем контроллере:

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

Итак, сначала вызов Expense.new здесь только создаст новый объект, но не сохранит его в базе данных; вам также нужно позвонить save, чтобы сделать это.

Далее, вы не возвращаете ответ вызывающему абоненту. Возможно, будет возвращено что-то вроде идентификатора нового расхода или самого расхода. Я бы предложил построить вызов так:

# 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-type заголовки, что хорошо, но вы также можете отправлять Accept заголовки, которые подскажут серверу, что вы ожидаете получить обратно:

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, часто помогает отлаживать такого рода ошибки связи, когда вы не знаете, является ли проблема ошибкой кодирования на стороне приложения или серверной кодировкой (или оба). Вы можете исключить переменные, используя что-то вроде curl, которое, как вы можете быть уверенным, сработает, а затем отладьте оттуда.

Надеюсь, это поможет вам!

...