【发布时间】:2023-03-24 00:45:01
【问题描述】:
我有一个自定义 rake 任务 (Mechanize),它(每小时)从某个网站获取订单信息,例如订单 ID、客户名称和订单状态,并将其保存到数据库中。
代码如下:
desc "Login to exampleShop, fetch all the order information, save it to the database"
task :task_1 => :environment do
require 'mechanize'
puts "BEGIN - Task 1 - Checking exampleShop for new orders"
a = Mechanize.new
a.get('http://exampleshop.nl/admin/') do |page|
# Select the login form
login_form = page.forms.first
# Insert the username and password
login_form.username = 'username'
login_form.password = 'password'
# Submit the login information
dashboard_page = a.submit(login_form, login_form.buttons.first)
# Check if the login was successfull
puts check_1 = dashboard_page.title == 'Dashboard' ? "CHECK 1 DASHBOARD SUCCESS" : "CHECK 1 DASHBOARD FAIL"
# Visit the orders index page to scrape some standard information
orders_page = a.click(dashboard_page.link_with(:text => /Bestellingen/))
# pp orders_page # => http://pastebin.com/L3zASer6
# Check if the visit is successful
puts check_2 = orders_page.title == 'Bestellingen' ? "CHECK 2 ORDERS SUCCESS" : "CHECK 2 ORDERS FAIL"
# Search for all #singleOrder table row's and put them in variable all_single_orders
all_single_orders = orders_page.search("#singleOrder")
# Print information to the console
puts "START fetching and saving information"
# Scrape the needed information (the actual save to database is omitted)
all_single_orders.each do |order|
# Set links for each order
order_link = order.at_css("a")['href'] #Assuming first link in row
order_id = order.search("#orderId").text
order_status = order.search("#orderStatus").text
order_revenue = order.search("#orderAmount").text
# Visit a single order page to fetch more detailed information
single_order_page = orders_page.link_with(:href => order_link).click
first_name = single_order_page.search(".firstName").text
last_name = single_order_page.search(".lastName").text
city = single_order_page.search(".city").text
postal_code = single_order_page.search(".postalCode").text
address = single_order_page.search(".address").text
email = single_order_page.search(".email").text
order_quantity = single_order_page.search(".orderQuantity").text
single_order = Order.create( order_id: order_id, first_name: first_name, last_name: last_name, city: city,
email: email, postal_code: postal_code, address: address, order_quantity: order_quantity,
order_revenue: order_revenue, order_status: order_status)
end
# Print information to the console
puts "DONE fetching and saving information"
end
puts "END - Task 1 - Checking exampleShop for new orders"
end
我不希望数据库变得混乱并设置唯一性验证器。这是当前的Order 模型:
class Order < ActiveRecord::Base
validates :order_id, uniqueness: true
end
这是一个场景草图:
# Point in time 1
order_status = "Order received"
# Point in time 2
order_status = "Order shipped"
当在时间点 1 时,rake 任务将获取所有相关的订单信息,order_status 将是“收到订单”。
在第 2 点时,rake 任务再次开始获取订单信息。但这次我希望它检查order_status 是否发生了变化,如果是,它必须在不向数据库添加新订单的情况下更新订单。
完成这项工作的最佳方法是什么?我正在使用 Rails 4.0.1 和 Ruby 2.0.0。
更新
问题是关于第二部分的。我希望代码检查 order_status 是否已更改,如果是,则必须使用新的 order_status 值更新相关订单。
更新 2
我已将以下内容添加到我的自定义 rake 任务中
single_order = Order.find_or_create_by(order_id: order_id, first_name: first_name, last_name: last_name, city: city,
email: email, postal_code: postal_code, address: address, order_quantity: order_quantity,
order_revenue: order_revenue, order_status: order_status)
unless single_order.valid?
single_order.order_status = order_status
puts single_order.save!
end
这给了我以下输出:
BEGIN - Task 1 - Checking exampleShop for new orders
CHECK 1 DASHBOARD SUCCESS
CHECK 2 ORDERS SUCCESS
START fetching and saving information
rake aborted!
Validation failed: Order has already been taken
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/validations.rb:57:in `save!'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/attribute_methods/dirty.rb:41:in `save!'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/transactions.rb:275:in `block in save!'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/transactions.rb:326:in `block in with_transaction_returning_status'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `block in transaction'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:210:in `within_new_transaction'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `transaction'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/transactions.rb:209:in `transaction'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/transactions.rb:323:in `with_transaction_returning_status'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/activerecord-4.0.1/lib/active_record/transactions.rb:275:in `save!'
/Users/username/Dropbox/Development/Rails/fstool/lib/tasks/task_1.rake:64:in `block (3 levels) in <top (required)>'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/nokogiri-1.6.0/lib/nokogiri/xml/node_set.rb:237:in `block in each'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/nokogiri-1.6.0/lib/nokogiri/xml/node_set.rb:236:in `upto'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/nokogiri-1.6.0/lib/nokogiri/xml/node_set.rb:236:in `each'
/Users/username/Dropbox/Development/Rails/fstool/lib/tasks/task_1.rake:39:in `block (2 levels) in <top (required)>'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/gems/mechanize-2.7.2/lib/mechanize.rb:434:in `get'
/Users/username/Dropbox/Development/Rails/fstool/lib/tasks/task_1.rake:9:in `block in <top (required)>'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/bin/ruby_executable_hooks:15:in `eval'
/Users/username/.rvm/gems/ruby-2.0.0-p353@global/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => task_1
(See full trace by running task with --trace)
【问题讨论】:
-
这里只是一个快速的警察检查。为什么要在循环中使用
@order_quantity等实例变量。这不是一个好习惯,您正在破坏那里的可见性。 -
因为我是初学者,所以总是欢迎好的练习技巧。谢谢。
标签: ruby-on-rails ruby activerecord ruby-on-rails-4