在console中强制class reloading

ror开发的一个强势就是其解释性勿须编译,对源文件的更改可以立即体现在运行中,当启动rails应用之后,可以运行ruby script/console对应用进行即时调试,比如对model进行query测试,检验find查询的语句编写和结果查看,好处是不用打开数据库控制台就可以进行数据库编程,在检查查询的同时也校验了程序的编写,提高了开发效率。最近在开发当中遇到个问题,就是development mod下启动rails应用之后,在console中做调试时发现对源文件的修改并不能立即生效,检查config/environments/development.rb配置,config.cache_classes = false,应该是支持类的重新加载,而通过browser发出请求,修改是生效的,如何解决这个问题?当然一个办法就是需要不停的关闭和重启rails应用,但是太麻烦了,后来查了一下网上的资源,发现可以在console当中输入‘reload!’强制rails进行类重新加载,问题得到解决。

config.cache_classes配置选项的设置意义如下:
[quote]
Without getting into too much nitty-gritty detail, when the config.cache_classes setting is true, Rails will use Ruby's require statement to do its class loading, and when it is false, it will use load instead.
[/quote]

至于require与load的不同,可以查看yjjxf的一篇文章:
[url]http://www.iteye.com/topic/79864[/url]
<template> <BasicModal v-bind="$attrs" @register="registerModal" :title="title" destroyOnClose width="60%" @ok="handleSubmit" @visible-change="visibleChange"> <BasicForm @register="registerForm"> <template #title="{ model, field }"> <div class="item"> <div class="title-view"> <div class="tag"></div> <div class="title">{{ model[field] }}</div> </div> </div> </template> <template #getTreeBtn> <a-button type="primary" @click="createTree">获取目录树</a-button> </template> <template #getTree> <div class="item"> <a-card :bordered="false" style="height: 100%"> <a-spin :spinning="loading"> <template v-if="treeData.length > 0"> <a-tree v-if="!treeReloading" checkable :clickRowToExpand="true" :treeData="treeData" :selectedKeys="selectedKeys" :checkStrictly="true" :load-data="loadChildrenTreeData" :checkedKeys="checkedKeysRef" v-model:expandedKeys="expandedKeys" @check="onCheck" @select="onSelect" @expand="onExpand" > <template #title="{ key: treeKey, title }"> <span>{{ title }}</span> </template> </a-tree> </template> <a-empty v-else description="暂无数据" /> </a-spin> </a-card> </div> </template> <template #ziduan> <editTable :taskType="2" :data="dataSource" @save="saveData" /> </template> </BasicForm> </BasicModal> </template> <script setup lang="ts"> import { ref, onMounted, defineEmits } from 'vue'; import { formSchema } from '../user.data'; import { BasicForm, useForm } from '/@/components/Form/index'; import { message } from 'ant-design-vue'; import { useUserStore } from '/@/store/modules/user'; import { dirList, saveOrUpdate } from '../user.api'; import { BasicModal, useModalInner } from '/@/components/Modal'; import editTable from '../../database/components/editTable.vue'; // 状态定义 const treeData = ref<any[]>([]); const checkedKeysRef = ref<string[]>([]); const selectedKeys = ref<string[]>([]); const expandedKeys = ref<string[]>([]); const loading = ref<boolean>(false); const treeReloading = ref<boolean>(false); const paths = ref<string[]>([]); const dataSource = ref(); const fieldInfoObj = ref(); const isUpdate = ref(false); const title = ref(); const editDeviceName = ref(); const emit = defineEmits(['success']); const deviceTypeOptions = ref(); // 初始化 onMounted(async () => { deviceTypeOptions.value = useUserStore().getAllDictItems['dc_device_type'] || []; }); // 表单配置 const [registerForm, { resetFields, setFieldsValue, validate, getFieldsValue }] = useForm({ labelWidth: 100, schemas: formSchema, showActionButtonGroup: false, baseColProps: { span: 12 }, }); // 递归查找 treeData 中匹配 path 的 key function findKeysByPaths(treeNodes: any[], pathsToMatch: string[]) { const keys: string[] = []; treeNodes.forEach((node) => { if (pathsToMatch.includes(node.path)) { keys.push(node.key); } if (node.children && node.children.length > 0) { keys.push(...findKeysByPaths(node.children, pathsToMatch)); } }); return keys; } // 查找 treeData 中匹配 path 的节点 function findNodeByPath(treeNodes: any[], path: string) { for (const node of treeNodes) { if (node.path === path) { return node; } if (node.children && node.children.length > 0) { const found = findNodeByPath(node.children, path); if (found) return found; } } return null; } // 递归加载路径上的所有节点 async function loadPathNodes(path: string, parentNode: any = null) { console.log('loadPathNodes: Processing path:', path); const segments = path.split('/').filter((seg) => seg); let currentPath = ''; let currentNodes = parentNode ? parentNode.children : treeData.value; let currentParent = parentNode; for (let i = 0; i < segments.length; i++) { currentPath = i === 0 ? `/${segments[0]}` : `${currentPath}/${segments[i]}`; let node = findNodeByPath(currentNodes, currentPath); console.log('loadPathNodes: Current path:', currentPath, 'Node found:', !!node); if (!node && currentParent && currentParent.izLeaf) { console.log('loadPathNodes: Loading children for:', currentParent.path); await loadChildrenTreeData({ dataRef: currentParent }); currentNodes = currentParent.children || []; node = findNodeByPath(currentNodes, currentPath); } if (node) { expandedKeys.value = [...new Set([...expandedKeys.value, node.key])]; if (node.izLeaf && i < segments.length - 1) { console.log('loadPathNodes: Preloading children for:', node.path); await loadChildrenTreeData({ dataRef: node }); } currentParent = node; currentNodes = node.children || []; } else { console.warn('loadPathNodes: Node not found for path:', currentPath); break; } } treeData.value = [...treeData.value]; // 强制更新 treeData console.log('loadPathNodes: Updated treeData:', treeData.value); } // 解析并加载所有路径的父节点 async function expandParentNodes(pathsToExpand: string[]) { console.log('expandParentNodes: Processing paths:', pathsToExpand); expandedKeys.value = []; for (const path of pathsToExpand) { await loadPathNodes(path); } console.log('expandParentNodes: Final expandedKeys:', expandedKeys.value); treeData.value = [...treeData.value]; // 确保响应式更新 } // 模态框初始化 const [registerModal, { closeModal }] = useModalInner(async (data) => { await resetFields(); isUpdate.value = data.isUpdate; if (data.isUpdate) { editDeviceName.value = data.record.deviceName; paths.value = data.record.configInfoObj.paths || []; fieldInfoObj.value = dataSource.value = data.record.fieldInfoObj || []; title.value = '修改任务'; await setFieldsValue({ ...data.record, ...data.record.configInfoObj, }); await new Promise((resolve) => setTimeout(resolve, 10)); await setFieldsValue({ deviceId: data.record.deviceId }); console.log('Modal init: paths:', paths.value); await handleTree(); if (paths.value.length > 0) { await expandParentNodes(paths.value); checkedKeysRef.value = findKeysByPaths(treeData.value, paths.value); console.log('Modal init: Backfill - paths:', paths.value, 'checkedKeys:', checkedKeysRef.value); } } else { fieldInfoObj.value = dataSource.value = []; paths.value = []; checkedKeysRef.value = []; title.value = '创建任务'; await setFieldsValue({ ...data.record, }); } }); // 将数据格式化为树结构 function formatTreeData(item: any, index: number) { return { title: item.name, key: `${item.path}-${item.name}-${index}`, izLeaf: item.izLeaf, isLeaf: !item.izLeaf, path: item.path, parentPath: item.parentPath, children: [], // 初始化 children 为空数组 }; } // 获取目录树 async function handleTree() { console.log('handleTree: Starting, current paths:', paths.value); const savedPaths = [...paths.value]; // 保存当前路径 const savedExpandedKeys = [...expandedKeys.value]; // 保存当前展开状态 let values = await getFieldsValue(); let params = { host: values.host, port: values.port, username: values.username, password: values.password, os: values.os, path: '/', }; console.log('handleTree: dirList params:', params); if (values.host && values.port && values.username && values.password && values.os) { try { loading.value = true; let data = await dirList({ ...params }); console.log('handleTree: dirList result:', data); if (!data || data.length === 0) { message.error('目录树数据为空,请检查FTP服务器配置'); treeData.value = []; paths.value = []; checkedKeysRef.value = []; expandedKeys.value = []; return; } treeData.value = data.map((item, index) => formatTreeData(item, index)); console.log('handleTree: Initial treeData:', treeData.value); autoExpandParentNode(); if (isUpdate.value && savedPaths.length > 0) { paths.value = savedPaths; // 恢复路径 console.log('handleTree: Restoring paths:', paths.value); await expandParentNodes(paths.value); // 重新加载深层路径 checkedKeysRef.value = findKeysByPaths(treeData.value, paths.value); expandedKeys.value = [...new Set([...expandedKeys.value, ...savedExpandedKeys])]; // 恢复展开状态 console.log('handleTree: After restore - paths:', paths.value, 'checkedKeys:', checkedKeysRef.value, 'expandedKeys:', expandedKeys.value); } } catch (error) { console.error('handleTree: Error:', error); message.error('获取目录树失败:' + error.message); treeData.value = []; paths.value = []; checkedKeysRef.value = []; expandedKeys.value = []; } finally { loading.value = false; } } else { message.info('请填写完整FTP服务器配置再获取目录树'); } } // 自动展开父节点 function autoExpandParentNode() { let item = treeData.value[0]; if (item && item.izLeaf) { expandedKeys.value = [...new Set([...expandedKeys.value, item.key])]; } console.log('autoExpandParentNode: expandedKeys:', expandedKeys.value); reloadTree(); } // 重新加载树 async function reloadTree() { treeReloading.value = true; await new Promise((resolve) => setTimeout(resolve, 0)); treeReloading.value = false; } // 动态加载子节点 async function loadChildrenTreeData(treeNode: any) { try { console.log('loadChildrenTreeData: Triggered for path:', treeNode.dataRef.path); if (treeNode.dataRef.izLeaf) { let values = await getFieldsValue(); let params = { host: values.host, port: values.port, username: values.username, password: values.password, os: values.os, path: treeNode.dataRef.path, }; console.log('loadChildrenTreeData: dirList params:', params); const result = await dirList(params); console.log('loadChildrenTreeData: dirList result:', result); if (result.length === 0) { treeNode.dataRef.izLeaf = false; treeNode.dataRef.isLeaf = true; } else { treeNode.dataRef.children = result.map((item, index) => formatTreeData(item, index)); treeNode.dataRef.isLeaf = false; // 确保有子节点时不标记为叶子节点 } treeData.value = [...treeData.value]; // 深拷贝触发响应式更新 if (isUpdate.value && paths.value.length > 0) { checkedKeysRef.value = findKeysByPaths(treeData.value, paths.value); console.log('loadChildrenTreeData: After load - checkedKeys:', checkedKeysRef.value); } } else { console.log('loadChildrenTreeData: Node is not a folder, izLeaf:', treeNode.dataRef.izLeaf); } } catch (e) { console.error('loadChildrenTreeData: Error:', e); message.error('加载子节点失败:' + e.message); } return Promise.resolve(); } // 展开事件 async function onExpand(expandedKeys: string[], { expanded, node }: { expanded: boolean; node: any }) { expandedKeys.value = expandedKeys; console.log('onExpand: Node:', node.path, 'Expanded:', expanded, 'izLeaf:', node.izLeaf); if (expanded && node.izLeaf && (!node.children || !node.children.length)) { await loadChildrenTreeData({ dataRef: node }); if (isUpdate.value && paths.value.length > 0) { for (const path of paths.value) { if (path.startsWith(node.path) && path !== node.path) { console.log('onExpand: Reloading deep path:', path); await loadPathNodes(path, node); } } } } } // 勾选事件 function onCheck(checkedKeys: any, info: any) { checkedKeysRef.value = Array.isArray(checkedKeys) ? checkedKeys : checkedKeys.checked; paths.value = info.checkedNodes.map((node: any) => node.path); console.log('onCheck: checkedKeys:', checkedKeysRef.value, 'paths:', paths.value); } // 选择事件 async function onSelect(selKeys: string[], event: any) { if (selKeys.length > 0 && selectedKeys.value[0] !== selKeys[0]) { selectedKeys.value = [selKeys[0]]; } } // 存储表格数据 function saveData(data: any[]) { if (data.length > 0) { fieldInfoObj.value = data.map(({ key, ...rest }) => rest); } else { fieldInfoObj.value = data; } } // 提交事件 async function handleSubmit() { if (!Array.isArray(paths.value) || paths.value.length === 0 || (paths.value.length === 1 && paths.value[0] === '')) { message.info('请选择文件目录,文件目录不能为空'); return; } try { let values = await validate(); const fieldInfo = JSON.stringify(fieldInfoObj.value); for (const obj of fieldInfoObj.value) { for (const key of Object.keys(obj)) { const value = obj[key]; if (value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0)) { message.info('表格数据不能为空'); return; } } } let configInfoObj = { host: values.host, port: values.port, username: values.username, password: values.password, os: values.os, paths: paths.value, fileNameMatchingRules: values.fileNameMatchingRules, matchKey: values.matchKey, fileType: values.fileType, readRow: values.readRow, }; const configInfo = JSON.stringify(configInfoObj); let params = { ...values, fieldInfo: fieldInfo, fieldInfoObj: fieldInfoObj.value, configInfoObj: configInfoObj, configInfo: configInfo, }; await saveOrUpdate(params, unref(isUpdate)); closeModal(); emit('success'); } finally { } } // 模态框可见性变化 function visibleChange(visible: boolean) { if (!visible) { treeData.value = []; checkedKeysRef.value = []; paths.value = []; expandedKeys.value = []; selectedKeys.value = []; } } async function createTree() { console.log('createTree: Starting fresh tree generation'); const values = await getFieldsValue(); const params = { host: values.host, port: values.port, username: values.username, password: values.password, os: values.os, path: '/', // 始终从根目录开始 }; if (!values.host || !values.port || !values.username || !values.password || !values.os) { message.info('请填写完整FTP服务器配置再获取目录树'); return; } try { loading.value = true; // 清空所有缓存数据 treeData.value = []; checkedKeysRef.value = []; expandedKeys.value = []; selectedKeys.value = []; const data = await dirList(params); console.log('createTree: Fresh tree data:', data); if (!data || data.length === 0) { message.error('目录树数据为空,请检查FTP服务器配置'); return; } // 生成全新树结构 treeData.value = data.map((item, index) => formatTreeData(item, index)); console.log('createTree: New treeData:', treeData.value); // 自动展开根节点(可选) if (treeData.value.length > 0) { expandedKeys.value = [treeData.value[0].key]; } } catch (error) { console.error('createTree: Error:', error); message.error('获取目录树失败:' + error.message); } finally { loading.value = false; reloadTree(); // 确保UI刷新 } } </script> <style scoped lang="less"> .item { margin-left: 10px; position: relative; .title-view { padding-bottom: 20px 20px 0 20px; display: flex; align-items: center; .tag { width: 5px; height: 18px; border-radius: 2rpx; background: #40a9ff; } .title { padding-left: 7px; font-size: 14px; font-weight: bold; } } } </style>当树树存在数据时,表单的values.host,values.port,values.username,values.password某一项发生修改则提示FTP服务器配置,重新获取目录树,并清空树的数据和paths.value,给我修改后的全部代码,用中文回答
最新发布
06-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值