根据时间更新属性 - Rails

时间:2016-08-24 21:32:39

标签: ruby-on-rails

我为咖啡店建立奖励系统。基本上,客户可以注册一年的订阅。现在,当他们注册active属性时,切换为true。我正在尝试编写一个方法,在一年过后将属性切换为false。我现在有一个方法,我想使用,但我不知道在哪里使用它?我也有一个失败的测试。为了清楚起见,我将展示我当前的代码。

控制器:

  def create
    @subscriber = Subscriber.new(subscriber_params)
    if @subscriber.save
      @subscriber.touch(:subscription_date)
      @subscriber.update(active: true)
      SubscriberMailer.welcome_subscriber(@subscriber).deliver_now
      flash[:notice] = "Subscriber Has Been Successfully Created"
      redirect_to new_subscriber_path(:subscriber)
    else
      render "new"
    end
  end

我想使用的模型方法:

    def not_active(subscriber)
    if subscription_date < 1.year.ago
      self.update(active: false)
    end
  end

测试失败:

  it "sets active to false after a year" do
    subscriber = create(:subscriber)
    subscriber.update(active: true)

    Time.now + 366.days

    expect(subscriber.active).to eq(false)
  end

所以希望这个想法很清楚。我只想更新为active:false如果用户是在一年前创建的。

3 个答案:

答案 0 :(得分:2)

您必须运行not_active方法才能使方法生效。该方法无法知道当前的日期和更新订户,除非它实际运行。我同意matt,你可能会在sidekiq job每日update!运行这种方法,对所有订阅了一年或更久以前并且处于活动状态的订阅者(你可以为此编写一个范围)。这样,您可以调用not_active方法并适当地设置每个订阅者的活动,或将其写为订阅者类方法并将其应用于范围的结果。在测试not_active方法本身的情况下,您需要做的就是调用它并测试结果。我也不清楚为什么not_active方法将订阅者作为arg,似乎从订阅者实例中调用它会更有意义。这不是什么事情已经发生了吗?我个人会称这种方法为deactivate!,因为它正在进行更改。 not_active类似的声音会返回布尔值或非活动订阅者。我还建议使用更新!而不是not_active中的更新。如果更新失败,rspec mocks将引发错误。添加到time.now确实会改变时间。如果需要,您可以使用{{3}}伪造当前时间。无论如何,这是not_active测试的样子:

it "sets active to false after a year" do
    subscriber = Subscriber.create(subscription_date: (1.year.ago - 1.day), active: true)

    #changed not_active to deactivate, called from instance instead of passing in subscriber
    subscriber.deactivate!

    expect(subscriber.active?).to eq(false)
end

您也可以为其他案例编写测试

it "does not deactivate a recent subscriber" do
    subscriber = Subscriber.create(subscription_date: Date.today, active: true)

    subscriber.deactivate!

    expect(subscriber.active?).to eq(true)
end

答案 1 :(得分:1)

对此的一个简单解决方案是使用cron。有一个与cron接口的rubygem,称为whenever。设置简单,文档齐全。

使用服务器上的cron设置,您可以创建某种类方法,该方法将遍历Subscribers,并调用not_active方法。

顺便说一句,如果在not_active模型中定义Subscriber方法,则您不需要将订阅者作为参数传递,因为self将隐式设置为订阅者。

代码最终会看起来像:

在subscriber.rb

def self.set_subscribers_to_inactive
  find_each(active: false) do |subscriber|
    subscriber.inactive!
  end
end

def inactive!
  update(active: false) if subscription_date < 1.year.ago
end

在schedule.rb

every 1.day do
  runner "Subscriber.set_subscribers_to_inactive"
end

如上所述,您的测试实际上并未调用not_active方法。

it "sets active to false after a year" do
  last_year = DateTime.current - 366.days
  subscriber = create(:subscriber, active: true, subscription_date: last_year)
  subscriber.inactive!

  expect(subscriber.active).to eq false
end

答案 2 :(得分:0)

查看cronwhenever gem,它位于cron之上。您只需要编写一个超级简单的脚本,它将从DB中提取数据并进行更新。

解决问题的另一种方法是不更新任何内容。您只需要*_expires_at列并检查其值是否小于当前日期。

这是非常灵活的方法,因为通过使用activation_expires_at列,您可以实现#active?方法和.active范围,以便仅选择具有有效订阅的用户。