Связь формы поиска в Ruby с Sinatra

У меня есть форма поиска, которую я использую с API YP (Желтые страницы), написанная на Ruby, с помощью Sinatra.

Мне удалось подключить все точки, чтобы поиск работал на серверной части, но у меня возникли проблемы с подключением формы поиска к вызову API. Все отображается правильно на странице, но ничего не отображается, когда я нажимаю кнопку отправки.

Код, который я использую ниже:

require 'rubygems'
require 'sinatra'
require 'yp'

# index.rb 

get "/" do
  # Only run the search if both of our params are available
  if params[:location] && params[:term]
  client = Yp::Client.new(api_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  results = client.search(searchloc: params[:location], term: params[:term], listingcount: 1, sort: 'distance')
  erb :index, :locals => {results: results}
end

__END__

@@index

<h1>YP Search</h1>

<form action="/" method="get">  
  Location: <input type="text" name="location">  <br />
  Search Term: <input type="text" name="term" required> <br />
<input type="submit">  
</form> 

<% if results %>
 <% results.each do |result| %>
 # Print out the result info
<% end %>
<% else %>
 # They haven't searched yet.
<% end %>

1 ответ

Решение

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

get "/" do
  # Only run the search if both of our params are available
  if params[:location] && params[:term]
  client = Yp::Client.new(api_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  @results = client.search(searchloc: params[:location], term: params[:term], listingcount: 1, sort: 'distance')
end

Эта строка:

  @results = client.search(searchloc: params[:location], term: params[:term], listingcount: 1, sort: 'distance')

становится телом. Вы хотите, чтобы отображаемый шаблон был последней строкой, поэтому:

get "/" do
  # Only run the search if both of our params are available
  if params[:location] && params[:term]
  client = Yp::Client.new(api_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  @results = client.search(searchloc: params[:location], term: params[:term], listingcount: 1, sort: 'distance')
  erb :index
end

Переменные экземпляра автоматически видны шаблонам, так что это все, что вам нужно сделать. Если вы хотите передать локальную переменную:

get "/" do
  # Only run the search if both of our params are available
  if params[:location] && params[:term]
  client = Yp::Client.new(api_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  results = client.search(searchloc: params[:location], term: params[:term], listingcount: 1, sort: 'distance')
  erb :index, :locals => {results: results}
end

а затем удалите @ от передней части @results Вар в шаблоне.

erb :index это вызов метода. Он говорит "вызовите рендерер шаблонов, используйте механизм ERB и передайте его :index template`. Возвращаемое значение метода - строка. Затем эту строку можно использовать где угодно, как обычную строку, но вы, скорее всего, скорее всего поместите ее в конец блока маршрута, поскольку вы хотите вернуть строку.

Там, где вы поместили его прямо сейчас, в теле класса, это просто вызов метода, результат которого ни к чему не приведет. Это то же самое, что и:

get "/you/can/access/this" do
  "and this would be the returned body"
end

get "/and/this" do
  erb :index, :locals=>{:what_youd_see => "would be the template"}
end

"But this is just a string that no one can access, it gets called every time, but who is the receiver?"

Думайте о своем приложении Sinatra как о классе, и тогда обычные правила Ruby станут понятнее:)


Я клонировал ваш репозиторий git и обнаружил несколько проблем:

  • Вам не нужно перечислять rubygems как зависимость в gemspec.
  • Дробовик не был указан в gemspec или Gemfile как зависимость для разработки.
  • Rails был указан, хотя его нет в проекте.

в гемспеке:

Gem::Specification.new do |gem|
  #other code
  gem.version       = Yp::VERSION
  gem.add_development_dependency "shotgun"
  gem.add_dependency('faraday', ["< 0.8", ">= 0.6"])    
  gem.add_dependency('faraday_middleware', [">= 0.8"])  
  gem.add_dependency('sinatra')  
end

Выше показано, как я изменил файл yp.gemspec, но лично я не помещаю зависимости разработки в gemspec, а в Gemfile.

# Gemfile

group :development do
  gem "shotgun"
end

Я думаю, что легче управлять и лучше разделять вещи. Вместо бега bundle install я бегу bundle install --binstubs --path vendor поскольку это помещает все в локальную директорию проекта. Таким образом, все проекты изолированы друг от друга, и вы заметите, если что-то пропустили. Чтобы запустить приложение, которое я использовал bundle exec ruby index.rb,

  • Были синтаксические ошибки с index.rb

использование ruby -c filename проверить на наличие синтаксических ошибок. Первое, что нужно попробовать, когда вы получаете ошибки при загрузке.

  • В Ruby вы должны закрыть, если... еще блокирует end,

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

get "/" do
  halt 400, "You need to supply a location and a term"
  # Only run the search if both of our params are available
  if params[:location] && params[:term]
    client = Yp::Client.new(api_key: "e89cba4b974a122e408d1723626f3709")
    results = client.search(searchloc: params[:location], term: params[:term], listingcount: 1, sort: 'distance')
  end
  erb :index, :locals => {results: results}
end
  • Вы жестко закодировали ключ API.

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

YAML.load_file("config/secret_settings.yml").each do |key,value|
  ENV[key.upcase] = value
end

Я добавляю это в Rakefile и запускаю приложение из файла стойки, например

namespace :app do

  desc "Set up the environment locally"
  task :environment do
    warn "Entering :app:environment"
    YAML.load_file("config/secret_settings.yml").each do |key,value|
      ENV[key.upcase] = value
    end
  end

  desc "Run the app locally"
  task :run_local => "app:environment" do
    exec "bin/rackup config.ru -p 4567"
  end
end

из командной строки:

bin/rake app:run_local

и вы, вероятно, захотите добавить config.ru,

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

Другие вопросы по тегам