Ruby on Rails 5.2 如何向第三方自定义Widget返回JSON搜索结果
跨域Widget搜索结果返回最优方案
不需要额外新增模型字段、不需要让客户引入第二个JS脚本,通过CORS配置+内置前端提交回调的方案即可实现需求,具体实现步骤如下:
1. 配置跨域资源共享(CORS)
首先安装rack-cors gem处理跨域请求权限:
# Gemfile gem 'rack-cors'
执行bundle install后新增CORS配置文件:
# config/initializers/cors.rb Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins '*' # 生产环境替换为客户实际域名,多个域名用逗号分隔 resource '*', headers: :any, methods: [:get, :post, :options] end end
2. 调整表单结构,预留结果容器
修改search_form.html.erb,去掉默认的remote: true配置,新增表单ID和结果容器:
<%= bootstrap_form_for @search, :html => {id: "search-widget-form"}, :url => create_search_url(@search) do |form| %> <%=form.select :beds, (select_options), {prompt: "Min # of Bedrooms", hide_label: true}, {class: "form-control form-control-sm"}%> <%=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"}%> <input type="submit" name="commit" value="SEARCH" class="btn btn-danger"> <% end %> <div id="search-widget-results" style="margin-top: 20px;"></div>
3. 内置提交回调逻辑到原有JS资源
修改SearchapisController的js_constructor方法,把表单提交、请求接口、渲染结果的逻辑直接打包到客户引入的search_form.js中,无需额外引入其他资源:
private def js_constructor form_content = render_to_string('search_form', layout: false) js_content = <<~JS document.write(#{form_content.to_json}); // 监听表单提交事件 document.getElementById('search-widget-form').addEventListener('submit', async function(e) { e.preventDefault(); const submitBtn = this.querySelector('input[type="submit"]'); const originalBtnText = submitBtn.value; submitBtn.disabled = true; submitBtn.value = 'Finding Schools...'; // 序列化表单数据发起请求 const formData = new FormData(this); const resultContainer = document.getElementById('search-widget-results'); resultContainer.innerHTML = ''; try { const res = await fetch('#{create_search_url}', { method: 'POST', body: formData }); const results = await res.json(); // 自定义结果渲染逻辑,可根据需求调整样式和字段 if(results.length > 0) { let html = '<h4>搜索结果</h4><ul class="search-results-list">'; results.forEach(item => { html += `<li>房源:${item.title} / 价格:${item.price}</li>`; }); html += '</ul>'; resultContainer.innerHTML = html; } else { resultContainer.innerHTML = '<p>暂无匹配的房源</p>'; } } catch(err) { resultContainer.innerHTML = '<p>搜索失败,请稍后重试</p>'; console.error('搜索请求错误', err); } finally { submitBtn.disabled = false; submitBtn.value = originalBtnText; } }); JS js_content end
4. 生产环境优化建议
- 将CORS配置中的
*替换为客户实际域名,避免接口被恶意调用 - 可新增客户身份校验逻辑,给每个接入的客户分配唯一标识,请求时携带校验,防止接口滥用
- 可对搜索结果渲染样式做统一封装,支持客户自定义配色等参数适配不同站点风格
内容的提问来源于stack exchange,提问作者tomb
相关产品推荐
相关产品推荐

