如何检查值是否已更改并更新数据库中的值?

时间:2013-12-12 12:06:58

标签: ruby-on-rails ruby activerecord ruby-on-rails-4

我有一个自定义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

我已将以下内容添加到自定义佣金任务

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)

1 个答案:

答案 0 :(得分:1)

嗯,

你可以做到

order = Order.new(order_params)
if order.valid? #no error on uniq
   order.save
end

我对你提到的最后一部分不太确定。 但您可以通过

检查order_status是否已更改
@order.order_status_changed?

这里是文档:

http://api.rubyonrails.org/classes/ActiveModel/Dirty.html

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)

if single_order.valid?
  single_order.save
else
  order = Order.find(order_id)
  order.order_status = "SOMETHING"
  order.save!
end