【问题标题】:On/off subscription attribute for railsRails 的开/关订阅属性
【发布时间】:2016-07-02 13:44:22
【问题描述】:

我目前有一个可以注册新订阅者的应用。当他们注册时,用户订阅了一年,我想说“如果一年到了,您的订阅现在将关闭,直到续订”。我最近向订阅者添加了一个名为status 的属性,并将其设置为字符串。我的想法是我可以做出一个 if/else 语句来为订阅者打开或关闭条件,但我不确定这是否是最好的主意?我的问题是 - 处理此类案件的最佳方法是什么?为了清楚起见,我将发布一些代码。

控制器:

   class SubscribersController < ApplicationController
  helper_method :sort_column, :sort_direction

  def index
    @search = Subscriber.search(params[:q])
    @subscriber = @search.result
    @search.build_condition if @search.conditions.empty?
    @search.build_sort if @search.sorts.empty?
  end

  def new
    @subscriber = Subscriber.new
  end

  def create
    @subscriber = Subscriber.create(subscriber_params)
    if @subscriber.save
      flash[:notice] = "Subscriber Has Been Successfully Created"
      redirect_to new_subscriber_path(:subscriber)
    else
      render "new"
    end
  end

架构:

    create_table "subscribers", force: :cascade do |t|
    t.string   "first_name"
    t.string   "last_name"
    t.string   "email"
    t.string   "phone_number"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
    t.integer  "visit"
    t.integer  "mug_number"
    t.string   "status"
  end

如您所见,一切都很基本。我只是主要寻求有关如何处理这种情况的建议。任何帮助都会非常感谢!

【问题讨论】:

  • 您可能需要查看 cron 和 whenever gem 以安排在年底运行“取消订阅”代码。

标签: ruby-on-rails ruby


【解决方案1】:

status 是不够的。您需要订阅日期。

架构

create_table "subscribers", force: :cascade do |t|
  t.string   "first_name"
  t.string   "last_name"
  t.string   "email"
  t.string   "phone_number"
  t.datetime "created_at",   null: false
  t.datetime "updated_at",   null: false
  t.integer  "visit"
  t.integer  "mug_number"
  t.date     "subscription_date"  # We don't neet status any more
end

# If you want to use subscription_date in the active way (see below)
add_index :subscribers, :subscription_date

您可以定义一个方法来判断用户是否仍在订阅。

您还可以将scope 添加到您的模型类中。

型号

class Subscriber
  scope :subscribing, -> {where subscription_date > 1.year.ago}
  scope :non_subscribing, -> {where.not subscription_date > 1.year.ago}

  def subscribing?
    !!(subscription_date && subscription_date > 1.year.ago)
  end
end

你有两种方式来使用这个状态。

被动(简单)方式

这样,您只需告诉用户他/她的订阅已结束(或即将结束)。

在您的视野中

<% unless @subscriber.subscribing? %>
<p>Your subscription is now turned off.</p>
<% end %>

如果用户没有访问您的网站,则什么也不会发生。

主动方式

您将拥有一个调度程序,每天获取非订阅用户并向他们发送通知(电子邮件、短信或移动推送)。

您可以使用 gem whenever 作为您的调度程序。

config/schedule.rb

every :day, at: '20:30' do
  rake 'notify_subscription_expiration'
end

lib/tasks/subscription.rake

task :notify_subscription_expiration => : environment do
  Subscriber.non_subscribing.find_each do |subscriber|
    # send notification
  end
end

【讨论】:

  • 谢谢! @Aetherus。我只有一个问题。我应该如何设置订阅日期?像on_create 这样的东西?你得到一个我的意思是......就像现在如果有人订阅subscription_date 是零。
  • @CameronBass subscriber.subscription_date = Time.now 在控制器或模型中使用before_create: guides.rubyonrails.org/…
  • @CameronBass 或before_save 但仅在nil 时设置,如subscriber.subscription_date ||= Time.now
【解决方案2】:

我建议我们有一个类似expired_at:datetime 的属性来指定订阅何时过期。

好的,现在很容易知道订阅者是否过期

class Subscriber < ActiveRecord::Base
  scope :expired, -> { where('expired_at > ?', Time.now }
end

剩下的问题是如何计算expired_at,这很容易,不是吗?我们可以在模型中实现回调,例如

class Subscriber < ActiveRecord::Base
  scope :expired, -> { where('expired_at > ?', Time.now }
  before_create :calculate_expired_at

  private

  def calculate_expired_at
     # If expired_at is not specified, make it expired 1 year after now
     self.expired_at ||= Time.now + 1.year
  end
end

这有点灵活,因为有一天你改变了你的策略,比如 2 年订阅,这个解决方案仍然可以处理这种情况!

另外,要让订阅者过期,再简单不过了,只需分配expired_at = Time.now

【讨论】:

    【解决方案3】:

    回答

    这是使用问题中提供的代码的解决方案。根据最佳实践和约定按需重构。

    1) 添加/expired 路由,用于渲染文本。可以将其更改为指向视图。

    # config/routes.rb
    get "expired" => "subscribers#expired", :as => :expired
    

    2) 添加before_filter,通过检查subscriber 是否已填充,在每个请求上检查经过身份验证的订阅者。我假设subscriber 等价于current_user

    check_for_subscription 检查订阅是否有效,如果无效,则将subscriber.status 更新为"expired",然后重定向到/expired 页面。

    如果subscriber.status 已经是"expired",过滤器将直接重定向到/expired 页面。

    # app/controllers/application_controller.rb
    class ApplicationController < ActionController::Base
      before_filter :check_for_subscription
    
      def check_for_subscription
        if subscriber
          case subscriber.status
    
          when "subscribed" then
            # check if today's date is within one year from subscriber creation
            # if not set status to expired and redirect to expired-page
            unless (subscriber.created_at..(subscriber.created_at + 1.year)).cover?(Date.today)
              subscriber.update_attributes(:status => "expired")
              redirect_to :expired_path
            end
    
          when "expired" then
            redirect_to :expired_path
          end
        end
      end
    
    end
    

    3) 向订阅者控制器添加expired 操作。此外,在创建操作中添加使用"subscribed" 填充subscriber.status

    # app/controllers/subscribers_controller.rb
    class SubscribersController < ApplicationController
      helper_method :sort_column, :sort_direction
    
      def expired
        render :text => "if the year is up your subscription is now turned off until renewal"
      end
    
      # […]    
    
      def create
        @subscriber = Subscriber.new(subscriber_params)
        @subscriber.status = 'subscribed'
    
        if @subscriber.save
          flash[:notice] = "Subscriber Has Been Successfully Created"
          redirect_to new_subscriber_path(:subscriber)
        else
          render "new"
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 2019-01-03
      • 2022-01-12
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-28
      • 2019-06-02
      • 2022-01-03
      相关资源
      最近更新 更多