Отправка данных GeoJSON с данными формы в приложение Rails 4

У меня есть веб-страница, которая создает «Активность». Используя простую форму, пользователь заполняет некоторую основную информацию о деятельности:

#new.html.erb
<%= simple_form_for @activity do |f| %>
    <%= f.input :name, label: "Activity name", input_html: { id: "create_activity_name_field" }, hint: "At least 7 characters" %>
    <%= f.input :type, label: "Activity type", input_html: { id: "create_activity_type_field" }, as: :select, :include_blank => false, collection: Activity.types.keys.to_a %>
    <%= f.input :date_field, input_html: { id: "create_activity_date_field" }, as: :string %>
    <%= f.input :time_field, input_html: { id: "create_activity_time_field" }, as: :string %>
    <% f.button :submit, :class => "btn btn-primary" -%>
<% end %>

Однако я также использую MapBox для отображения карты. Пользователь будет щелкать точки на карте, чтобы проложить маршрут для занятия. Когда пользователь закончит рисовать маршрут, я могу извлечь данные GeoJSON для этого маршрута.

Я хотел бы использовать javascript для POST данных GeoJSON с данными формы. На серверной части я заставлю rails преобразовать GeoJSON в файл KML и использовать Paperclip для загрузки его в Amazon S3. Остальные данные можно сохранить, и Paperclip предоставит мне URL-адрес файла KML, который я могу связать с действием.

Я новичок в Rails, и я не могу понять, как это сделать, и не могу отследить что-нибудь, чтобы преодолеть это препятствие. Я подумал об использовании javascript FormData. Меня очень привлек этот подход, потому что реализация выглядит очень простой, но, по-видимому, она может действительно обрабатывать только пары ключ/значение, а не сложные вложенные данные JSON.

Любые предложения или стратегии с благодарностью. И очень признателен ++, если кто-нибудь может дать подробные ответы, потому что, как я уже сказал, я всего несколько недель новичок в рельсах и веб-разработке.


person niborg    schedule 06.09.2015    source источник


Ответы (2)


Что вы, вероятно, захотите сделать здесь, так это предотвратить поведение вашей формы по умолчанию, используя JS:

$('form').submit(function(e) { 
 e.preventDefault();
 var form = $('form');
 var form_data_json = JSON.stringify(form.serializeArray());
 form_plus_geojson = form_data_json.concat(Geojson);

Возьмите свои данные в JS (это должно быть легко, но вы на самом деле не говорите, как вы извлекаете данные из mapbox).

Затем отправьте данные обратно через AJAX (не забывайте о проверке на обоих концах)

if (my_data_is_not_good/empty/whatever) { 
    console.log('nop')
 } else {
         $.ajax({ 
         type: 'post',
         url: Yourcontrollerpostaction, 
         data: form_plus_geojson,
         dataType: "JSON",

После того, как данные были отправлены, вы хотите возобновить нормальное поведение после отправки формы и отправить форму.

         complete: function() { 
            this.off('submit');
            this.submit();
         }
     });
 }

});

Затем вам просто нужно проанализировать данные в вашем контроллере.

def post_controller
  if request.xhr?
    my_hash = JSON.parse(params[:mydata]) 
  else 
    normal post behavior 
  end
end

Все это быстрый псевдокод, вам, возможно, придется что-то исправить, поскольку я его не тестировал, но он должен работать. Очевидно, что теперь, когда мы делаем все в ajax, вам не нужен обратный вызов функции завершения, и вы можете удалить эту часть.

person jayD    schedule 06.09.2015
comment
Но с двумя почтовыми запросами я имею дело с двумя отдельными действиями контроллера, не так ли? Создает хакерский бэкэнд-код. Но мне нравится ваша идея о присоединении к геоджсону с постом json. Собираюсь рассмотреть возможность этого. - person niborg; 07.09.2015
comment
Нет, не совсем. В rails вы можете обрабатывать несколько типов данных на одном контроллере. Это очень распространено. И есть несколько способов сделать это. Вот один: if request.xhr? handle the json data else normal post behavior end - person jayD; 07.09.2015
comment
Я имею в виду, что моему действию контроллера сначала придется обрабатывать geojson без данных формы. Но я не хочу хранить геоджсон в своих моделях, не зная данных формы. Поэтому мне пришлось бы найти способ временно удерживать его, пока контроллер не получит данные формы, а затем проверить и сохранить все. - person niborg; 07.09.2015
comment
На самом деле вы можете просто объединить оба объекта json и отправить их с помощью ajax. используя jsonArray1 = jsonArray1.concat(jsonArray2); и передать его как данные. это должно сработать. Я редактирую свой ответ. Кроме того, чтобы ответить на ваш вопрос, вы могли бы просто создать новый экземпляр и сохранить его только при наличии данных формы. но уже не надо. - person jayD; 08.09.2015

Престижность @jDay за то, что указал мне правильное направление - особенно с объединением данных JSON. Однако мне не удалось заставить его конкретное решение работать в моем приложении, и я попробовал другой метод, который, на мой взгляд, был немного более простым.

Я использовал гем Rails simple_form_for для создания формы, указав удаленный почтовый вызов:

#new.html.erb
<%= simple_form_for @activity, :url => '/activities', :method => :post, :remote => true, html: {id: :activity_create_form, "data-type" => :json} do |f| %>
    <%= f.input :name, label: "Activity name", input_html: { id: "create_activity_name_field" }, hint: "At least 7 characters" %>
    <%= f.input :type, label: "Activity type", input_html: { id: "create_activity_type_field" }, as: :select, :include_blank => false, collection: Activity.types.keys.to_a %>
    <%= f.input :date_field, input_html: { id: "create_activity_date_field" }, as: :string %>
    <%= f.input :time_field, input_html: { id: "create_activity_time_field" }, as: :string %>
    <%= f.button :submit, :class => "btn btn-primary", input_html: {id: "create_activity_submit_btn"} -%>
<% end %>

Затем я использовал jQuery, чтобы перехватить кнопку отправки формы и добавить невидимый элемент формы, несущий данные GeoJSON. Однако данные должны были быть преобразованы в строки, чтобы их можно было отправить:

#activity_new.js
$("form").submit( function (e) {
        e.preventDefault();

        $('<input />')
                    .attr('type', 'hidden')
                    .attr('name', 'routeGeoJson')
                    .attr('value', JSON.stringify(polyline.toGeoJSON()))
                    .appendTo(this);
        return true;
});

(Здесь «polyline» — это объект Leaflet L.polyline, который я использовал для рисования на карте.)

В контроллере вы получите такие параметры:

{"utf8"=>"✓", "activity"=>{"name"=>"Прогулка в лесу", "type"=>"прогулка", "date_field"=>"2015-09-08" , "time_field"=>"07:00"}, "routeGeoJson"=>"{\"тип\":\"Функция\",\"свойства\":{},\"геометрия\":{\" type\":\"LineString\",\"координаты\":[[-118.38855654001236,33.95361274499209],[-118.36624056100845,33.97681937760982]]}}", "commit"=>"Создать действие", "контроллер"=> "деятельность", "действие"=>"создать"}

Поскольку данные «routeGeoJson» все еще находятся в строковой форме, я повторно собрал данные GeoJSON, проанализировав их с помощью гема JSON (который, как я полагаю, включен по умолчанию в Rails 4):

def create
   geojson = JSON.parse(params[:routeGeoJson])
   # do something...
end

И вы получаете свой хэш GeoJSON:

{"type"=>"Feature", "properties"=>{}, "geometry"=>{"type"=>"LineString", "coordinates"=>[[-118.420142233337173, 33.98407904797006], [-118.37825685739517, 33,956175751601826]]}}

person niborg    schedule 08.09.2015