Отправка данных ответа JSON в пользовательский виджет — Ruby Rails 5.2

#javascript #widget #ruby-on-rails-5 #jsonresponse

Вопрос:

Я создаю виджет, который клиент может отображать на своем стороннем веб-сайте. Виджет принимает информацию от потребителей о том, какой дом они ищут. При отправке виджет делает запрос на публикацию в модели поиска в API конечной точки (моя база данных). Затем я хочу отобразить результаты поиска на веб-сайте клиента.

До сих пор я успешно размещал форму поиска на стороннем веб-сайте, и при отправке создается новый объект поиска, и результаты поиска готовы для просмотра на моем веб-сайте. Но я хочу, чтобы результаты поиска были отправлены обратно на веб-сайт клиента.

На веб-сайте клиента у них есть js-скрипт, который выглядит следующим образом:

 lt;script type="text/javascript" src="http://localhost:3000/searchapis/search_form.js"gt;lt;/scriptgt;  

Мои маршруты.рб:

 get 'searchapis/show' get '/searchapis/:template', to: "searchapis#show" post 'search/create', to: "searches#create"  

Я создал контроллер searchesapi, который выглядит следующим образом:

 class SearchapisController lt; ApplicationController  protect_from_forgery :except =gt; :show    def show  @search = Search.new    respond_to do |format|  format.html { render params[:template], layout: 'searchapis' }  format.js { render js: js_constructor }  end  end    private  def js_constructor  content = render_to_string(params[:template], layout: false)  "document.write(#{content.to_json})"  end end  

Я создал search_form.html.erb представление, которое выглядит примерно так:

 lt;%= bootstrap_form_for @search, :html =gt; {}, :url =gt; create_search_url(@search), remote: true do |form| %gt;  lt;%=form.select :beds, (select_options), {prompt: "Min # of Bedrooms", hide_label: true}, {class: "form-control form-control-sm"}%gt;  lt;%=form.select :max_price, (100000..2000000).step(10000).map{|x| number_to_currency(x, precision: 0)}, {hide_label: true, prompt: "Select Max Price"}, {class: "form-control form-control-sm", id: "sale_price"}%gt;  lt;input type="submit" name="commit" value="SEARCH" class="btn btn-danger" data-disable-with="Finding Schools..."gt;  

И, наконец, searches_controller.rb:

 class SearchesController lt; ApplicationController  skip_before_action :verify_authenticity_token  before_action :set_search, only: [:show, :edit, :update, :destroy]  before_action :require_admin, only: [:index, :destroy]   def create  @search = Search.new(search_params)   respond_to do |format|  if @search.save   format.html { redirect_to @search, notice: 'Search was successfully created.'}  results = @search.listings  p results #this is what I want to send to the third party site  format.json { render json: results.to_json, remote: true, notice: "Search results below"}  end  end  end end  

Теперь отображается форма, и при отправке создается новый поиск, но я не уверен, как продолжить, чтобы результаты поиска можно было отправить через ответ JSON на сторонний веб-сайт.

Я думаю, что мне нужно будет создать дополнительный src javascript для веб-сайта клиента = ( lt;script type="text/javascript" src="http://localhost:3000/searchapis/api_search_results.js"gt;lt;/scriptgt; ), связанного с новой страницей api_search_results, и мне это понадобится rails g migration AddNewSttributeToSearch api:boolean , чтобы я мог выполнить поиск api в контроллере и перейти на новую страницу api_search_results. Затем, когда потребитель нажимает «Отправить» на стороннем веб-сайте, 2-й src javascript отобразит результаты, но я думаю, что, возможно, есть лучший способ. Есть какие — нибудь мысли на этот счет?

Комментарии:

1. Почему бы не использовать iframe? Визуализируйте эту форму в iframe, и у вас будет полный контроль над тем, что находится внутри нее.

2. Спасибо за комментарий @razvans, я попробую. Но как только iframe будет на месте, и потребитель введет свои данные, и данные будут переданы в мою базу данных, и поиск будет проведен, и результаты будут готовы, как мне затем отобразить эти результаты на экране потребителя? Теоретически на веб-сайте клиента могут быть сотни людей, поэтому результаты должны соответствовать каждому запросу.

Ответ №1:

Я, наконец, понял это. В том же представлении, в котором есть форма, я создал таблицу для хранения данных и некоторый javascript для отображения ответа json. Новое действие «search_results» обрабатывает прием данных формы, создание поиска и возврат json.

Обновленные маршруты:

 get 'searchapis/search_results'  post 'searchapis/search_results'  get 'searchapis/show'  get '/searchapis/:template', to: "searchapis#show"  

Обновленное представление формы поиска:

 lt;%= bootstrap_form_for @search, :html =gt; {id: "search_api"}, :url =gt; searchapis_search_results_url(@search), remote: true do |form| %gt;  lt;%=form.select :beds, (select_options), {prompt: "Min # of Bedrooms", hide_label: true}, {class: "form-control form-control-sm"}%gt;  lt;%=form.select :max_price, (100000..2000000).step(10000).map{|x| number_to_currency(x, precision: 0)}, {hide_label: true, prompt: "Select Max Price"}, {class: "form-control form-control-sm", id: "sale_price"}%gt;  lt;input type="submit" name="commit" value="SEARCH" class="btn btn-danger" data-disable-with="Finding Schools..."gt;  lt;% end %gt;  

Обновленный контроллер для отображения формы, принятия данных формы, создания поиска и возврата результатов с помощью json:

 class SearchapisController lt; ApplicationController  protect_from_forgery :except =gt; [:show, :search_results]    def show  @search = Search.new  @search.api_search = true    respond_to do |format|  format.html { render params[:template], layout: 'searchapis' }  format.js { render js: js_constructor }  end  end    def search_results  @search = Search.new(search_params)  @search.save  @results = @search.listings  response = @results.map{|x| [x[0].name,x[0].address,x[0].city,x[0].performance_stats.find_by(year: "1819").rating,x[1].count]}  render json: response.to_json  end     private  def js_constructor  content = render_to_string(params[:template], layout: false)  "document.write(#{content.to_json})"  end    #note, I had to copy search_params from the SearchesController, so perhaps the search_results method could be added to the Searches Controller to avoid this   def search_params  params.require(:search).permit(:name, :address, :city)  end end  

SearchesController Создать действие:

 respond_to do |format|  if @search.save  if @search.api_search == true  return  end  *additional routing*  end end  

Представление search_form теперь выглядит следующим образом:

 lt;stylegt;  #hide_table {  display:none  } lt;/stylegt;  lt;%= bootstrap_form_for @search, :html =gt; {id: "search_api"}, :url =gt; searchapis_search_results_url(@search), remote: true do |form| %gt;  lt;%=form.select :beds, (select_options), {prompt: "Min # of Bedrooms", hide_label: true}, {class: "form-control form-control-sm"}%gt;  lt;%=form.select :max_price, (100000..2000000).step(10000).map{|x| number_to_currency(x, precision: 0)}, {hide_label: true, prompt: "Select Max Price"}, {class: "form-control form-control-sm", id: "sale_price"}%gt;  lt;input type="submit" name="commit" value="SEARCH" class="btn btn-danger" data-disable-with="Finding Schools..."gt;  lt;% end %gt;    lt;div class="container-fluid"gt;  lt;div class="row"gt;  lt;div class="col"gt;  lt;div id='hide_table'gt;  lt;table class="table table-sm" id="schools_api"gt;  lt;theadgt;  lt;trgt;  lt;thgt;Namelt;/thgt;  lt;thgt;Addresslt;/thgt;  lt;thgt;Citylt;/thgt;  lt;thgt;Scorelt;/thgt;  lt;thgt;# Homeslt;/thgt;  lt;/trgt;  lt;/theadgt;  lt;tbodygt;  lt;/tbodygt;  lt;/tablegt;  lt;/divgt;  lt;/divgt;  lt;/divgt; lt;/divgt;  lt;scriptgt; document.body.addEventListener("ajax:success", (event) =gt; {  var response = event.detail[0];  $("#schools_api tbody tr").remove();   $('#hide_table').css("display","block");  $.each(response, function(i, item) {  $('lt;trgt;').html("lt;tdgt;"   item[0]   "lt;/tdgt;lt;tdgt;"   item[1]   "lt;/tdgt;lt;tdgt;"   item[2]   "lt;/tdgt;lt;tdgt;"   item[3]   "lt;/tdgt;lt;tdgt;"   item[4]   "lt;/tdgt;").appendTo('#schools_api');  });  });  lt;/scriptgt;