2015/07/28

クエリレコード作成と番組自動予約

手動で予約~録画、視聴の流れはできたかな。次は自動予約だ。
前回はRedmineプラグインだったので制約が結構あったが、今回は自由がある。
その代わり面倒なところもある。

Queryモデル作成

$ rails g  scaffold query title:string start_time:time end_time:time query_type_id:integer category_id:integer sub_category_id:integer priority:integer

Queryレコード作成・変更・削除が必要なのでscaffoldで生成したコードを全部使用する。

query_type_idは、予約:1か検索:2を示す部分で、自動予約処理で使用する。
予約したいわけじゃなく「今日のゴールデンタイムのドラマは?」 を見たいときは検索タイプ。

start_timeとend_timeは、日時ではなく時間帯を指定したいので datetime ではなく time 型である。

priorityは将来的なもので、自動予約で時間がバッティングした場合、どちらを優先するのか?を設定しておくことで勝ち負けも自動でやらせようかという思惑。

models/query.rbの中身
# -*- coding: utf-8 -*-
class Query < ActiveRecord::Base
  belongs_to :category, -> { where cate_type: 0 }
  belongs_to :sub_category, -> { where cate_type: 1 }, class_name: 'Category'
  belongs_to :query_type

  def list
    programs = Program.all
    programs = programs.where(category_id: category_id) if category.present?
    programs = programs.where(category2_id: sub_category_id) if sub_category.present?
    programs = programs.where("title like :name", name: "%#{title}%") if title.present?

    # todo: 時間がセットされていないと判断する賢い方法はないのか?
    unless start_time.strftime("%H%M") + end_time.strftime("%H%M") == '00000000'
      programs = programs.where("TIME(start_at) >= TIME(?) and TIME(start_at) <= TIME(?)",
                                start_time, end_time)
    end
    return programs
  end

end

queryのlistメソッドで条件にマッチした番組リストを返す。条件が設定されているかどうかを値が入っているかどうかで判断したいけど、time型の場合が厄介。

f.time_selectでblankありにして、blank設定のままでも"0:00"になってしまう。nilにならない。

これをどうしたら良いの?という記事はいくつか見つかる。
http://stackoverflow.com/questions/14367705/time-select-blank-field-saves-a-default-time-when-form-is-submitted
とかで語られているソリューションがほとんど。だけど自分の肌に合わなかったので、
start_time.strftime("%H%M") + end_time.strftime("%H%M") == '00000000'
と、若干強引な方法で確認する羽目となった。

検索結果表示は、番組リスト(Program#index)で済ませる
内部処理はこんな↓
    @q = Program.where(video_id: nil).ransack(params[:q])
    if params[:query_id].present?
      @programs = Query.find_by(params[:query_id]).list
    else
      @programs = @q.result
    end
    @programs = @programs.order(:start_at).page(params[:page])
query_id付きで呼ばれた場合と普通の時で処理分け。
ransackも機能する必要があるので、@qの処理はどっちでもやる。

自動予約

繰り返し実行なのでActiveJobではなく、rake task にして whenever で回す。
タスクはすごく単純。 予約タイプのQueryレコードから条件にマッチする番組の予約をするだけ。
# -*- coding: utf-8 -*-
namespace :query do

  desc "自動予約"
  task :reserve => :environment do
    Query.where(query_type_id: 1).each do |q|
      q.list.where(video_id: nil).where('start_at > ?',Time.now+60).each do |program|
        program.reserve
      end
    end
  end

end

予約済みや、今より過去の番組を予約しないように、若干の条件付けを施す程度。
これだけで結構ちゃんと機能している。
以前に書いた処理に比べれば大分シンプルにまとまったような気がする。

これで全体機能は一段落ですが、実際に運用し始めるとまた色々問題が出るんですよねぇ。

0 件のコメント:

コメントを投稿