Rails 4 - 预加载依赖 select 导致错误(Rails4/Active 管理员)
Rails 4 - eager loading on dependent select causing error (Rails4/Active Admin)
我有一个带有依赖项 select 的活动面板,即第一个下拉菜单中的选择 select 会影响第二个下拉菜单中显示的内容。
几个月前一切正常,但我昨天才意识到它不再工作了。
我设法找到导致错误的原因:如果我删除预加载 ("include"),它会再次运行。
不工作:(当前版本):
@deal_subsectors = DealSector.find(params[:deal_sector_id],
include: :deal_subsectors).dealsubsectors
我收到此错误(来自 chrome 开发工具的控制台)
GET http://localhost:3000/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=2 404 (Not Found)
send @ jquery.js?body=1:9660
jQuery.extend.ajax @ jquery.js?body=1:9211
jQuery.(anonymous function) @ jquery.js?body=1:9357
jQuery.extend.getJSON @ jquery.js?body=1:9340
update_deal_subsector @ active_admin.js?body=1:19
(anonymous function) @ active_admin.js?body=1:12
jQuery.event.dispatch @ jquery.js?body=1:4666
elemData.handle @ jquery.js?body=1:4334
ListPicker._handleMouseUp @ about:blank:632
工作,当我删除 "include" / 预加载时:
@deal_subsectors = DealSector.find(params[:deal_sector_id]).deal_subsectors
在那种情况下效果很好。
但我真的很想加载交易子行业,所以我想知道是什么导致了这个错误,自从它工作以来发生了什么变化。我有一些假设,但找不到罪魁祸首。
Rails 4 改变了我应该使用 find(params[:id]..) 的方式还是我应该使用预加载的方式
活动管理员是否更改了它处理预先加载的方式:也许它只适用于索引而不适用于编辑页面...
Rails4 上的 turbolinks 是否改变了我必须预加载的方式?
代码如下:
- 活跃管理员
ActiveAdmin.register Deal do
# controller for the multi-select sector/subsector in the form
# does 2 things at same time: creates method and automatically defines the route of the method defined in controller
if params[:deal_sector_id] # pass the id
@deal_subsectors = DealSector.find(params[:deal_sector_id], include: :deal_subsectors).dealsubsectors
else
@deal_subsectors = []
end
render json: @deal_subsectors
end
end
- 有2个依赖的表格selects
form do |f|
f.inputs "Client" do
f.input :deal_sector_id,
:label => "Select industry:",
:as => :select,
:prompt => true,
:collection => DealSector.order("name").all.to_a
f.input :deal_subsector_id,
:label => "Select subindustry:",
:as => :select,
:prompt => true,
:collection => DealSubsector.order("name").all.to_a
end
end
- javascript 为其供电:
// for edit page
var deal_subsector = { };
$(document).ready(function() {
$('#deal_deal_sector_id').change(function() {
update_deal_subsector();
});
});
function update_deal_subsector() {
deal_sector_id = $('#deal_deal_sector_id').val(); //get the value of sector id
url = '/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=' + deal_sector_id; //make a query to the url passing the deal sector id as a parameter
$.getJSON(url, function(deal_subsectors) {
console.log(deal_subsectors);
$('#deal_deal_subsector_id').html("") //just blanks the id, blank it before populating it again if sector changes
for( i = 0; i < deal_subsectors.length; i++) {
console.log(deal_subsectors[i]);
$('#deal_deal_subsector_id').append("<option value=" + deal_subsectors[i].id + ">" + deal_subsectors[i].name + "</option>")
};
}); //pass the url and function to get subsector ids and all we get is assigned to the variable subsector_id
};
// for index page (filters)
$(document).ready(function() {
$('#q_deal_sector_id').change(function() {
update_deal_subsector_filter();
});
});
function update_deal_subsector_filter() {
deal_sector_id = $('#q_deal_sector_id').val(); //get the value of sector id
url = '/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=' + deal_sector_id; //make a query to the url passing the deal sector id as a parameter
$.getJSON(url, function(deal_subsectors) {
console.log(deal_subsectors);
$('#q_deal_subsector_id').html("") //just blanks the id, blank it before populating it again if sector changes
for( i = 0; i < deal_subsectors.length; i++) {
console.log(deal_subsectors[i]);
$('#q_deal_subsector_id').append("<option value=" + deal_subsectors[i].id + ">" + deal_subsectors[i].name + "</option>")
};
}); //pass the url and function to get subsector ids and all we get is assigned to the variable subsector_id
};
已添加文件
class DealSector < ActiveRecord::Base
has_many :deal_subsectors
end
class DealSubsector < ActiveRecord::Base
belongs_to :deal_sector, :foreign_key => 'deal_sector_id'
end
当您调用 ActiveRecord::find
时 – 这意味着您希望从数据库中获得一个单一的模型。
然后,您引用此模型并调用 dealsubsectors
– 我假设它与您的模型有 has_many
关系。它将产生 2 个查询:第一个是获取原始 DealSelector
,第二个是所有相关的 DealSubsectors
。
没有什么可以优化的(除非你 dealsubsectors
是模型中的自定义方法,而不是关系)。
如果您发现某些东西通过查询访问您的数据库 – 您必须在另一个地方查看。比方说,您的表格——您是否在每个表格中只显示一个客户?如果不是,它将为每个新客户迭代并再次获取所有 DealSector 和 DealSubsector。尽量提供更多代码。
为什么不能只获取给定 sector_id
的所有 DealSubsector 记录?
DealSubsector.where(deal_sector_id: params[:deal_sector_id])
Rails 4 对预加载算法进行了一些更改。
您可以根据自己的情况尝试以下代码片段:
@deal_subsectors = DealSector.eager_load(:deal_subsectors).find(params[:deal_sector_id]).dealsubsectors
或
@deal_subsectors = DealSector.includes(:deal_subsectors).find(params[:deal_sector_id]).dealsubsectors
第一个将在单个查询中获取数据,而第二个将进行两次查询。
我有一个带有依赖项 select 的活动面板,即第一个下拉菜单中的选择 select 会影响第二个下拉菜单中显示的内容。
几个月前一切正常,但我昨天才意识到它不再工作了。
我设法找到导致错误的原因:如果我删除预加载 ("include"),它会再次运行。
不工作:(当前版本):
@deal_subsectors = DealSector.find(params[:deal_sector_id],
include: :deal_subsectors).dealsubsectors
我收到此错误(来自 chrome 开发工具的控制台)
GET http://localhost:3000/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=2 404 (Not Found)
send @ jquery.js?body=1:9660
jQuery.extend.ajax @ jquery.js?body=1:9211
jQuery.(anonymous function) @ jquery.js?body=1:9357
jQuery.extend.getJSON @ jquery.js?body=1:9340
update_deal_subsector @ active_admin.js?body=1:19
(anonymous function) @ active_admin.js?body=1:12
jQuery.event.dispatch @ jquery.js?body=1:4666
elemData.handle @ jquery.js?body=1:4334
ListPicker._handleMouseUp @ about:blank:632
工作,当我删除 "include" / 预加载时:
@deal_subsectors = DealSector.find(params[:deal_sector_id]).deal_subsectors
在那种情况下效果很好。
但我真的很想加载交易子行业,所以我想知道是什么导致了这个错误,自从它工作以来发生了什么变化。我有一些假设,但找不到罪魁祸首。
Rails 4 改变了我应该使用 find(params[:id]..) 的方式还是我应该使用预加载的方式
活动管理员是否更改了它处理预先加载的方式:也许它只适用于索引而不适用于编辑页面...
Rails4 上的 turbolinks 是否改变了我必须预加载的方式?
代码如下:
- 活跃管理员
ActiveAdmin.register Deal do
# controller for the multi-select sector/subsector in the form
# does 2 things at same time: creates method and automatically defines the route of the method defined in controller
if params[:deal_sector_id] # pass the id
@deal_subsectors = DealSector.find(params[:deal_sector_id], include: :deal_subsectors).dealsubsectors
else
@deal_subsectors = []
end
render json: @deal_subsectors
end
end
- 有2个依赖的表格selects
form do |f|
f.inputs "Client" do
f.input :deal_sector_id,
:label => "Select industry:",
:as => :select,
:prompt => true,
:collection => DealSector.order("name").all.to_a
f.input :deal_subsector_id,
:label => "Select subindustry:",
:as => :select,
:prompt => true,
:collection => DealSubsector.order("name").all.to_a
end
end
- javascript 为其供电:
// for edit page
var deal_subsector = { };
$(document).ready(function() {
$('#deal_deal_sector_id').change(function() {
update_deal_subsector();
});
});
function update_deal_subsector() {
deal_sector_id = $('#deal_deal_sector_id').val(); //get the value of sector id
url = '/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=' + deal_sector_id; //make a query to the url passing the deal sector id as a parameter
$.getJSON(url, function(deal_subsectors) {
console.log(deal_subsectors);
$('#deal_deal_subsector_id').html("") //just blanks the id, blank it before populating it again if sector changes
for( i = 0; i < deal_subsectors.length; i++) {
console.log(deal_subsectors[i]);
$('#deal_deal_subsector_id').append("<option value=" + deal_subsectors[i].id + ">" + deal_subsectors[i].name + "</option>")
};
}); //pass the url and function to get subsector ids and all we get is assigned to the variable subsector_id
};
// for index page (filters)
$(document).ready(function() {
$('#q_deal_sector_id').change(function() {
update_deal_subsector_filter();
});
});
function update_deal_subsector_filter() {
deal_sector_id = $('#q_deal_sector_id').val(); //get the value of sector id
url = '/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=' + deal_sector_id; //make a query to the url passing the deal sector id as a parameter
$.getJSON(url, function(deal_subsectors) {
console.log(deal_subsectors);
$('#q_deal_subsector_id').html("") //just blanks the id, blank it before populating it again if sector changes
for( i = 0; i < deal_subsectors.length; i++) {
console.log(deal_subsectors[i]);
$('#q_deal_subsector_id').append("<option value=" + deal_subsectors[i].id + ">" + deal_subsectors[i].name + "</option>")
};
}); //pass the url and function to get subsector ids and all we get is assigned to the variable subsector_id
};
已添加文件
class DealSector < ActiveRecord::Base
has_many :deal_subsectors
end
class DealSubsector < ActiveRecord::Base
belongs_to :deal_sector, :foreign_key => 'deal_sector_id'
end
当您调用 ActiveRecord::find
时 – 这意味着您希望从数据库中获得一个单一的模型。
然后,您引用此模型并调用 dealsubsectors
– 我假设它与您的模型有 has_many
关系。它将产生 2 个查询:第一个是获取原始 DealSelector
,第二个是所有相关的 DealSubsectors
。
没有什么可以优化的(除非你 dealsubsectors
是模型中的自定义方法,而不是关系)。
如果您发现某些东西通过查询访问您的数据库 – 您必须在另一个地方查看。比方说,您的表格——您是否在每个表格中只显示一个客户?如果不是,它将为每个新客户迭代并再次获取所有 DealSector 和 DealSubsector。尽量提供更多代码。
为什么不能只获取给定 sector_id
的所有 DealSubsector 记录?
DealSubsector.where(deal_sector_id: params[:deal_sector_id])
Rails 4 对预加载算法进行了一些更改。 您可以根据自己的情况尝试以下代码片段:
@deal_subsectors = DealSector.eager_load(:deal_subsectors).find(params[:deal_sector_id]).dealsubsectors
或
@deal_subsectors = DealSector.includes(:deal_subsectors).find(params[:deal_sector_id]).dealsubsectors
第一个将在单个查询中获取数据,而第二个将进行两次查询。