Method works in development but not production Rai

2019-03-04 03:26发布

问题:

I have a Coupon class and I want my app to check and see how many counts are left on the coupon and if the date for the coupon has expired. I have the following method in my class to check both of these.

Coupon class

  def self.get(code)
   where(
    :code => (normalize_code(code)),
    :$and => [
      {
       :$or => [
         { :coupon_count.gte => 1  },
         { :coupon_count    => nil }
       ]
     }, {
       :$or => [
         { :expires_at.gt => Time.now.utc },
         { :expires_at    => nil      }
      ]
     }
    ]
  ).first
 end

This works fine in development when I enter a coupon. But in production it does not work. I use my MongoDB shell to create a coupon as follows.

db.Coupon.insert({code:'#COUPONNAME',discount_percent: 10, expires_at: new ISODate("2016-05-18"), coupon_count: 10, "description": '1st cold visit sign-up'})

It seems that the problem is when the Coupon checks the expires_at date. In development it finds the coupon and works but in production it keeps not finding the coupon. Just for good measure here is my controller method for this.

EDIT I thought the issue was with the date but if I remove the date query it still does not work in production. I am confused why this wont work in production. It is using MongoDB 3.0.10 and mongoid 5.1.0 gem


charges_controller
  @code = params[:couponCode]

if !@code.blank?
  @coupon = Coupon.get(@code)

  if @coupon.nil?
    flash[:error] = 'Coupon code is not valid or expired.'
    redirect_to new_managers_charge_path(id: @reportapproval.id)
    return
  elsif @coupon.discount_percent == 100
    @reportapproval.report_paid = true
    @reportapproval.free_coupon_used = true
    @reportapproval.save!
    @coupon.coupon_count = @coupon.coupon_count - 1
    @coupon.save!
    redirect_to managers_dashboard_path, :notice => "You have successfully requested a pre-paid report from #{@reportapproval.tenant_last_name} with a 'No-Pay' intro coupon."
    return
  else
    @final_amount = @coupon.apply_discount(@amount.to_i)
    @discount_amount = (@amount.to_i - @final_amount.to_i)
  end

回答1:

If you have a Coupon Mongoid model then the collection in the MongoDB shell would be db.coupons. That would explain why:

db.Coupon.insert(...)

in the MongoDB shell isn't providing what you're expecting to find in your Rails code.


As far as Neil's comment about $exists versus explicit nil checks goes, I think you really do want nil (AKA null inside MongoDB) checks. Consider this in the MongoDB shell:

> db.models.insert({ n: 11 })
> db.models.insert({ n: 0 })
> db.models.insert({ n: null })
> db.models.insert({ })
> db.models.find()
{ "_id" : ObjectId("571546e1ce2934dadf379479"), "n" : 11 }
{ "_id" : ObjectId("571546e4ce2934dadf37947a"), "n" : 0 }
{ "_id" : ObjectId("571546e7ce2934dadf37947b"), "n" : null }
{ "_id" : ObjectId("571546ecce2934dadf37947c") }

So we have a collection with documents that have n, don't have n, have explicit null values for n, and non-null values for n.

Then we can see the difference between Mongoid queries like :n => nil:

> db.models.find({ n: null })
{ "_id" : ObjectId("571546e7ce2934dadf37947b"), "n" : null }
{ "_id" : ObjectId("571546ecce2934dadf37947c") }

and :n.exists => true (AKA :n => { :$exists => true }):

> db.models.find({ n: { $exists: true } })
{ "_id" : ObjectId("571546e1ce2934dadf379479"), "n" : 11 }
{ "_id" : ObjectId("571546e4ce2934dadf37947a"), "n" : 0 }
{ "_id" : ObjectId("571546e7ce2934dadf37947b"), "n" : null }

and :n => { :$exists => false }:

> db.models.find({ n: { $exists: false } })
{ "_id" : ObjectId("571546ecce2934dadf37947c") }

So the :expires_at => nil queries will find documents which don't have an expires_at as well as documents where expires_at was explicitly set to nil. Both those cases will happen with Mongoid unless you're careful to call remove_attribute instead of assigning a nil and both cases mean "no expiry date".