Задний план (изменено после переписки с @TomLord):
Я создаю простой сайт только с индексной страницей и без подстраниц. На странице индекса есть поле «поиска», которое принимает ввод (id
) и отправляет запрос GET в RESTful API, работающий в фоновом режиме. Ответ API - JSON {"market price": "4306057.0", "retail price": "4995000.0"}
.
Я хочу отобразить этот результат на странице индекса вместе с полем поиска. Однако при нажатии на кнопку результат нигде не отображается.
Код:
index.html.erb
<section id = "search">
<div class = "container">
<%= form_tag({controller: "model_request", action: "result"}, method: "get", remote: true) do %>
<%= label_tag(:q, "Search for") %>
<%= text_field_tag(:q, "913384637") %>
<%= submit_tag("Get the price!") %>
<% end %>
</div>
</section>
<section id = "display_result">
<div class = "container">
</div>
</section>
А вот modelrequest_controller.rb
выглядит так:
class ModelrequestController < ApplicationController
def result
id = params['q'].capitalize
response = RestClient::Request.execute(
method: :get,
url: "http://0.0.0.0:80/?id=#{id}")
@result = JSON.parse response
respond_to do |format|
format.js {render layout: false}
end
end
end
Мой routes.rb
Rails.application.routes.draw do
root 'index#index'
match "/modelrequest", to: "modelrequest#result", via: 'get'
end
JavaScript для результатов выглядит так:
result.js.erb
$("#display_result").html("<%= escape_javascript(render partial: 'modelrequest/result', locals: { result: @result } ) %>");
А простой _result.html.erb
для отображения партиала -
<div id = "display_result">
<%= @result %>
</div>
Вывод:
Started GET "/model_request?utf8=%E2%9C%93&q=913384637&commit=Get%20the%20price!" for 127.0.0.1 at 2018-12-19 20:55:33 +0100
Processing by ModelRequestController#result as JS
Parameters: {"utf8"=>"✓", "q"=>"913384637", "commit"=>"Get the price!"}
Rendering model_request/result.js.erb
Rendered model_request/_result.html.erb (0.8ms)
Rendered model_request/result.js.erb (6.8ms)
Completed 200 OK in 383ms (Views: 11.6ms | ActiveRecord: 0.0ms)
Кроме того, обратите внимание на remote: true
в форме. Вы хотите, чтобы это был запрос AJAX, а не полная перезагрузка страницы.
Привет, @TomLord, спасибо за вклад. Я отредактировал свой пост и обновил код.
Идея состоит в том, чтобы вы отметили «div
результатов» на странице индекса. Назовем это .results
. Затем в show.js.haml
вы обновляете содержимое этого контейнера. Так что-то вроде: $(".results").html("#{escape_javascript(......
. Вы можете называть этот контейнер как хотите (#main
?), Но он должен присутствовать на этой странице.
Кроме того, в вашем случае это форма, который должен отправлять данные удаленно; здесь нет необходимости в link_to
. Например, см. korenlc.com/remote-true-in-rails-forms. Мы не меняем способ работы вашей формы; мы меняем только то, что рендерится в конце. Первоначально вы визуализировали новую страницу; теперь мы заменяем содержимое div
на той же странице.
Дорогой @TomLord, еще раз спасибо! Метод GET
для API теперь работает, индексная страница может загружаться, и нажатие кнопки фактически приводит к запросу к API, который отвечает правильно. Ура! Однако я все еще не могу добиться правильного отображения результата. Вроде ищет шаблон, не смотря на {render layout: false}
в контроллере. Я изменил код своего вопроса на обновленную версию.
Да, шаблон ищет - правильно. Вы назвали контроллер ModelrequestController
, что означает, что он ищет app/views/modelrequest/result.js.erb
. Однако вы назвали файл app/views/model_requests/result.js.erb
. Либо переименуйте папку, либо переименуйте контроллер в ModelRequestsController
.
Это то, о чем вам сообщает сообщение об ошибке :)
Здорово. Глупая ошибка. Теперь вроде все работает, осталось только разобраться, как вывести результат в index.html.haml. Если вы напишете свой комментарий в качестве ответа (частично), я с радостью его приму. Спасибо!
На "обычном" сайте rails форма поиска работает следующим образом:
Вы определяете форму в представлении. По умолчанию данные POST
передаются в конечную точку, но вы также можете сделать это с помощью запроса GET
. В вашем случае вы изначально выбрали:
form_tag("/search", method: "get")
Это синхронно отправит данные формы на GET /search
и, следовательно, выполнит полную перезагрузку страницы.
Это совершенно правильный поступок. Однако вы хотели оставаться на главной странице - поэтому запрос должен быть асинхронным:
form_tag("/search", method: "get", remote: true)
... Но теперь эта конечная точка должна делать что-то другое. Вместо рендеринга новой страницы ей нужно частично обновить текущую страницу.
Стандартный подход к этому в приложении rails - сделать что-то вроде:
# In the controller action, e.g. SearchController
def show
@results = # ...
respond_to do |format|
format.js {render layout: false}
end
end
# In the view, e.g. `search/show.js.erb`
$("#display_result").html("<%= escape_javascript(render partial: 'results', locals: { results: @results } ) %>");
# In an HTML partial, e.g. `search/_results.html.erb`
<% results.each do %>
...
Ключевая идея состоит в том, что на вашей главной странице (index.html.erb
?) У вас должен быть контейнер для отображения результатов. Затем вместо визуализации новой страницы вы просто визуализируете обновление HTML внутри этого контейнера.
Это, конечно, не единственный способ сделать это. Современные веб-сайты часто вместо этого извлекают данные JSON для результатов поиска, а затем определяют, как их отображать, с помощью JavaScript.
Однако описанный выше подход является наиболее "минимальным" изменением вашего текущего дизайна - без необходимости добавлять дополнительные шаблоны проектирования, вы можете оставить большую часть существующих шаблонов haml
/ erb
как есть и просто добавить небольшой код для визуализации результатов. как частичное.
Привет том! Я принял твой ответ. Я думаю, что понимаю общую структуру, и я заставил ее работать, если я не использую respond_to do |format| ...
, а просто вызываю @result
с link_from(...
, поэтому результат появляется в сообщении, когда я нажимаю ссылку. Однако рендеринг части по-прежнему не работает, хотя я определяю контейнер для отображения результата (см. Код выше). Единственное различие, которое я вижу, это _results.html.erb
, тогда как мой - просто <div id = "display_result"> <%= @result %> </div>
. Я подозреваю, что мой контейнер неправильно определен в index.html.erb
.
Просто потратил полчаса, пытаясь понять, почему моя партиал перестала работать, и это было так: "$ (" # display_result "). Html (" ... Я удалил или изменил идентификатор контейнера, отображающего js. шлепает лбом Ура!
Вы можете определить
show.js.erb
(илиshow.js.haml
), чтобы заменить содержимое контейнера (возможно,div
) с результатами поиска. Что-то вроде: stackoverflow.com/a/35900332/1954610