我构建了一个依赖于我目前使用Nokogiri解析的XML Feed的网站。虽然我的管理控制器中目前有所有代码,所以我可以通过URL /admin/import/
实际调用导入。
我不禁想到这不属于控制器。有没有更好的方法来执行此操作,即将代码移动到独立的import.rb
文件中,以便只能从控制台访问?如果是这样,我需要在/lib/
目录中放置此文件?
以下是代码段:
class AdminController < ApplicationController
def import
f = File.open("#{Rails.root}/public/feed.xml")
@doc = Nokogiri::XML(f)
f.close
ignore_list = [] # ignore list
@doc.xpath("/*/product[not(name = following-sibling::product/name)]").each do |node|
if !ignore_list.include? node.xpath("./programName").inner_text.strip
Product.create(:name => clean_field(node.xpath("./name").inner_text).downcase,
:description => clean_field(node.xpath("./description").inner_text),
:brand => Brand.find_or_create_by_name(clean_field_key(node.xpath("./brand").inner_text).downcase),
:merchant => Merchant.find_or_create_by_name(clean_field_key(node.xpath("./programName").inner_text).downcase),
:image => node.xpath("./imageUrl").inner_text.strip,
:link => node.xpath("./productUrl").inner_text.strip,
:category => Category.find_or_create_by_name(clean_field_key(node.xpath("./CategoryName").inner_text).downcase),
:price => "£" + node.xpath("./price").inner_text.strip)
print clean_field(node.xpath("./name").inner_text).downcase + "\n"
end
end
end
end
答案 0 :(得分:4)
您的代码听起来像是作为Rails运行脚本运行时效果很好。它们是在您网站的正常Rails流程之外运行的脚本,但可以完全访问ActiveRecord设置,因此您可以轻松访问数据库。
我不认为Rails对文件的位置和所有其他文件一样严格,但是我会在'app'下创建一个名为'scripts'的子目录并将其放在那里。保持整洁的目录结构对维护是一件好事。
您没有说您是在运行Rails 3还是以前的版本。如果您正在运行Rails 3,请在Rails应用程序的命令行中键入rails runner -h
以获取更多信息。
有些人认为脚本应该使用rake运行,我同意 IF 他们正在操纵文件和文件夹,并对应用程序运行的rails-space进行一般维护。如果你'重新执行作为数据库管理的一部分的定期任务,或者,在您的情况下,检索用于支持您的应用程序的内容,我认为它应该是一个“跑步者”任务。
您可以构建功能,这样您仍然可以触发代码通过URL运行,但我认为有可能滥用它,特别是如果您可以覆盖所需数据或用重复/冗余数据填充数据库。我认为通过操作系统发起的cron定期运行任务会更好,只是为了保持良好的间隔,或者只是手动运行。如果您通过URL访问保持可用,我建议您使用密码来避免滥用。
最后,作为一直在这么做的人,我建议您在代码中使用一些结构和对齐方式:
Product.create(
:name => clean_field(node.xpath("./name").inner_text).downcase,
:description => clean_field(node.xpath("./description").inner_text),
:brand => Brand.find_or_create_by_name(clean_field_key(node.xpath("./brand").inner_text).downcase),
:merchant => Merchant.find_or_create_by_name(clean_field_key(node.xpath("./programName").inner_text).downcase),
:image => node.xpath("./imageUrl").inner_text.strip,
:link => node.xpath("./productUrl").inner_text.strip,
:category => Category.find_or_create_by_name(clean_field_key(node.xpath("./CategoryName").inner_text).downcase),
:price => "£" + node.xpath("./price").inner_text.strip
)
简单的对齐可以帮助您维护代码,或者帮助保持最终维护代码的人员的理智。我可能会看起来像:
Product.create(
:name => clean_field( node.xpath( "./name" ).inner_text ).downcase,
:description => clean_field( node.xpath( "./description" ).inner_text ),
:brand => Brand.find_or_create_by_name( clean_field_key( node.xpath( "./brand" ).inner_text ).downcase ),
:merchant => Merchant.find_or_create_by_name( clean_field_key( node.xpath( "./programName" ).inner_text ).downcase ),
:image => node.xpath( "./imageUrl" ).inner_text.strip,
:link => node.xpath( "./productUrl" ).inner_text.strip,
:category => Category.find_or_create_by_name( clean_field_key( node.xpath( "./CategoryName" ).inner_text ).downcase ),
:price => "£" + node.xpath( "./price" ).inner_text.strip
)
但那只是我。我喜欢有更多的空格,特别是当有嵌套方法时,我喜欢在常用/类似函数之间进行一些垂直对齐。我发现它可以更轻松地扫描代码并查看任何差异,这有助于您在调试或查找特定内容时。再一次,这只是我的偏好,但这是我多年来用很多不同语言编写代码时学到的东西。
答案 1 :(得分:3)
我的一些应用程序中有类似的功能。我通常把这个逻辑放在一个类中,例如Importer
。这样我就可以从控制台使用它,并制作一个访问控制的控制器动作,让其他人从网上使用它。你把这个类放在哪里并不是非常重要,只要它在应用程序的加载路径中。我倾向于将我的应用程序/模型与/ lib放在一起,这样我就不需要在进行更改时重新加载应用程序。