我无法相信我还没有找到其他问题来回答这个问题,但我已经搜索过高低,无法找到真正回答我问题的任何问题。
基本上,我有一个费用页面,我想在表格中显示给定月份内的所有费用。我有一个月份和年份选择,现在我通过向网址添加月份和年份参数并使用一些小的javascript转到该href。我想避免页面刷新,只是在更改选择框值时更新表。据我了解,因为我没有使用表单,所以我不能使用:remote => true
因此必须使用AJAX。我的研究让我设置如下。
这是我带有AJAX调用的JQuery:
$(document).ready(function() {
$('#monthSelect').change(function() {
// alert("yay");
var m = $(this).val();
var y = $("#yearSelect").val();
$.ajax({
type: "GET",
url: "/expenses",
data: { month : m, year : y } ,
success: function(data) {
},
dataType: "json"
});
});
});
#monthSelect
和#yearSelect
是我的两个选择框的ID。这部分似乎有效。当我更改月份选择框的值时,它会在"/expenses"
中将正确的月份和年份的GET请求发送到params
。
/expenses
自然会路由到我的index
操作。这是我感到困惑的部分。
def index
@expenses = # Code that gets the expenses that correspond to the month and year in the params.
# This part works. I've tested it and @expenses are all the records I want
respond_to do |format|
format.html
format.json { render json: @expenses, status: :ok } #?????
end
end
所以我想我的主要问题是json部分是如何工作的,以及我是否应该在AJAX中使用json。我所看过的教程和视频似乎都暗示在json中获取响应是你应该这样做的方式,但我不确定是什么"渲染json&#34 ;甚至意味着。我的理解是传递@expenses
,它基本上会呈现@expenses.to_json
返回的内容,这只是一堆json,键值对。我该怎么做并制作一张桌子?
我的一位朋友已经做了很多AJAX,但没有Ruby on Rails说我可以在AJAX成功函数中编写HTML
...
success: function(data) {
$("#expenses-table").html("HTML of my Table");
}
但是,这似乎并不像Rails方式,只是放了一堆只是将HTML放入字符串的Javascript代码。如果我只是将HTML放在AJAX中,那么render: json
会怎么做?我确实在Stack Overflow上看到了答案
success: function(data) {
$("#expenses-table").html(data);
}
这将是不错的,因为数据确实拥有我想要的所有json。但显然这并不像那样。
所以,如果我能对这整个混乱局部得到一些澄清,如果我甚至用JSON接近它,或者我应该在AJAX中编写HTML,那将非常感激。
编辑1: 这是我目前的表格代码:
<table id="expenses">
<thead>
<tr>
<th>Description</th>
<th>Amount</th>
<th>User</th>
<th>Date</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @expenses.each do |expense| %>
<tr id="expenses-row">
<td><%= expense.description %></td>
<td><%= number_to_currency expense.amount %></td>
<td><%= expense.user.name %></td>
<td><%= expense.date.strftime("%m/%Y") %></td>
<td><%= link_to 'Show', expense %></td>
<% if expense.user == @user %>
<td><%= link_to 'Edit', edit_expense_path(expense) %></td>
<td><%= link_to 'Delete', expense, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<% else %>
<td></td>
<td></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
基本上只是标准的脚手架表。大多数变化只是css。这里是json对于一条记录的样子
[{"id":8,"description":"This is a test","amount":"35.0","user_id":1,"date":"2014-10-01","created_at":"2014-10-03T07:07:53.412Z","updated_at":"2014-10-03T07:07:53.412Z","receipt_file_name":null,"receipt_content_type":null,"receipt_file_size":null,"receipt_updated_at":null}]
我想我更喜欢ERB / ruby中的代码,因为我更熟悉它。虽然使用json几乎感觉有点无意义,因为@expenses是我已经在我当前的表代码中使用的。但是,不会渲染:file&#34; expenses_table.html.erb&#34;刷新整个页面?或者它如何知道在哪里渲染该表并替换以前的表?回复format.js
并制作index.js.erb
几乎听起来更容易,因为我知道我可以用部分代替html。但是我没有尝试过,因为我见过的所有例子都回复format.json
。如果听起来我只是困惑而且不知道发生了什么,因为我是。我只需要澄清一下。谢谢你的帮助!
答案 0 :(得分:3)
如果我甚至应该在AJAX中使用json。
您可以使用任何类型的String。问题是解析javascript端的字符串以提取每个数据。例如,您可以使用String响应,例如:
"exp1=10, exp2=20, exp3=30"
然后你的javascript代码可以将字符串拆分为&#34;,&#34;,然后&#34; =&#34;签名,然后使用碎片创建一个对象,然后您可以使用该对象来引用数据。另一方面,如果数据是作为JSON字符串发送的,那么您在javascript中所要做的就是:
var obj = JSON.parse(data);
...和obj将类似于ruby Hash,在那里你可以查找键来获取值。
所以我想我的主要问题是json部分如何工作......我的 理解是传递@expenses,它基本上会呈现什么 @ expenses.to_json返回,这只是一堆json,键值 对。我该怎么做并制作一张桌子?
那是对的。你使用自己的编程技巧制作表格。
我的一个朋友已经做了很多AJAX但没有Ruby on Rails 说我可以在AJAX成功函数中编写HTML
当然,但诀窍仍然是以编程方式获取json中的数据并将其插入到html表中。如果你想走那条路,你可以返回一个完整的表作为响应,这样你就可以在服务器端使用ERB / Nokogiri / ruby在表中插入数据。然后你会写一些类似的东西:
@expenses = ....
render :file "/some/dir/expenses_table.html.erb"
另一种方法可能是为表中的每个<td>
提供一个id属性,该属性等于json数据中的一个键。然后,您可以使用javascript循环遍历json数据中的每个键,查找具有该id的<td>
,然后将该条目替换为与该键对应的json数据中的值。
如果你想要更具体的建议,你必须发布你的表格的一个小例子以及@ expenses.to_json的样子。
顺便说一句,jQuery ajax()函数有太多的功能,所以所有常见的ajax请求都有快捷功能,其中相关的选项为你填写,例如getJSON()
,您只需指定网址,数据和成功功能。在这种情况下,这并不能为您节省大量工作,但函数名称可能比#ajax&#39;更具描述性。
对评论问题的回复:
我想我的困惑就是这个javascript是什么?这是 原来的AJAX电话?
是。这是您需要编码的唯一JavaScript。
那应该在js.erb文件中然后给我 打电话给一些红宝石代码?
没有。如果你想使用ruby创建一些js(这就是erb的用途),你会使用js.erb文件,并且你想要返回js代码作为响应。我们已经确定您不想将javascript作为回复返回。但是,使用rails来设置ajax是非常令人困惑的,所以我可能不理解你的问题的要点。不使用rails生成ajax javascript更简单。
据我所知,如果您在创建html表单时将remote: true
放在rails html帮助器中,那么在提交表单时,会向您的rails应用程序发送一个请求,其中包含Accept标头text/javascript
。这意味着如果您的操作具有带有format.js
行的respond_to块,则该行将执行,并且您可以将一些javascript发送回浏览器,例如一个.js.erb
文件,其中包含执行ajax请求以获取费用数据的代码。您的浏览器将立即执行返回的js,它将向服务器发送ajax请求,询问费用数据。请注意,rails方式效率低下:浏览器必须向服务器发送两个请求以完成一个ajax请求:一个请求被发送到服务器以获取将对费用数据发出ajax请求的js代码,然后是浏览器执行ajax代码,该代码向服务器发送另一个请求以获取费用数据。
或者我可以在回复中调用javascript文件 至?
在我看来,您希望用一个全新的表替换现有的表,即您不会在现有表中更改两个或三个<td>'s
,这应该会使事情变得非常简单。实际上,据我所知,您可以使用与创建现有表相同的erb代码来创建新表。但是,您的索引操作对ajax请求的响应应该只返回表 - 而不是整个页面。这表明你应该将创建表的代码放入一个单独的模板,部分:
views/shared/_table.html.erb
:
<table id="expenses">
<thead><th>Description</th><th>Amount</th><th>Date</th></thead>
<% @expenses.each do |expense| %>
<tr>
<!-- I used an abbreviated Expense model: -->
<td><%= expense.description %></td>
<td><%= number_to_currency expense.amount %></td>
<td><%= expense.date %></td>
</tr>
<% end %>
</table>
然后将部分包含在views/expenses/index.html.erb
:
<h1>Expenses#index</h1>
<p>Find me in app/views/expenses/index.html.erb</p>
<div>
<select id='expense_day'>
<option value="all">All</option>
<option value="2014-10-5">10/5/14</option>
<option value="2014-10-6">10/6/14</option>
</select>
</div>
<%= render "shared/table" %> <!-- HERE -->
默认情况下,render()将在名为shared/_table.html.erb
的app / views目录中查找部分内容。
这两个文件组合在一起(插入到应用程序布局中)构成了index.html.erb视图。因为该表现在是一个单独的模板,所以只能呈现该表以响应ajax请求:
class ExpensesController < ApplicationController
def index
respond_to do |format|
if request.xhr? #Is this an ajax request?
target_date_str = params['target_date']
if target_date_str == "all"
@expenses = Expense.all
else
@expenses = Expense.where(date: Date.strptime(target_date_str, "%Y-%m-%d"))
end
#Render just the table for the ajax request:
format.html { render partial: "shared/table" }
else #then not an ajax request
@expenses = Expense.all
format.html #By default renders index.html.erb
end
end
end
end
respond_to()
查看请求中的Accept标头,并根据它选择匹配的格式:
format.html
format.json
format.xml
etc.
我检查了jQuery的.get()ajax函数发送的请求,并发送了一个请求,其中text/html
的Accept标头为最高优先级,因此format.html将在respond_to阻止。 编辑:我最初编写了索引操作,认为ajax请求会有一个format.json行,非ajax请求会有一个format.html行。但是因为索引操作现在在两种情况下都返回html,所以不需要respond_to()块:
class ExpensesController < ApplicationController
def index
if request.xhr? #if an ajax request...
target_date_str = params['target_date']
if target_date_str == "all"
@expenses = Expense.all
else
@expenses = Expense.where(date: Date.strptime(target_date_str, "%Y-%m-%d"))
end
render partial: "shared/table" #Overrides rails default operation which renders index.html.erb
else #then not an ajax request
@expenses = Expense.all #rails defaults to rendering index.html.erb
end
end
以下是我使用的javascript:
<script>
$( document ).ready(function() {
$("#expense_day").on("change", function() {
var selected_date = $(this).val();
$.get(
"/expenses",
{ target_date: selected_date },
function(table) {
$("#expenses").replaceWith(table)
}
);
});
});
</script>
<h1>Expenses#index</h1>
<p>Find me in app/views/expenses/index.html.erb</p>
<div>
<select id='expense_day'>
<option value="all">All</option>
<option value="2014-10-5">10/5/14</option>
<option value="2014-10-6">10/6/14</option>
</select>
</div>
<%= render partial: "shared/table", expenses: @expenses %>
我将javascript放在index.html.erb视图中,这应该清楚地表明javascript是html页面的一部分。但是,您可以从index.html.erb中删除javascript并将其放在另一个文件中 - 但最终js必须找回index.html.erb文件。以下是一些讨论javascript的替代位置的链接:
Why is rails not rendering the .js.erb file?
Best way to add page specific javascript in a Rails 3 app?
Rails有一个名为asset pipeline
的东西,它是一种通过删除所有空格将所有javascript和css塞入尽可能少的行的方法。由于文件较小,因此您的浏览器可以更快地加载它们。要利用 minifying ,您必须将assets
(即您的javascript和css文件)放入某些目录中。这真的不是你需要担心的事情,因为你的javascript代码不是几千页。