質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

3回答

10661閲覧

【Rails】一定期間が経過したら、自動的にデータを削除するアクションを実装し、その変更を確認するバリデーションを持ちたい

jusco

総合スコア80

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

2クリップ

投稿2015/08/03 11:17

あるデータが作成されてから、一定期間が経過したらアプリ側で自動的にそのデータの状態が変わり、変わるまでは新規でデータ作成ができない、という機能を実装したいです。

具体的な仕様は以下のようなものです。

・UserモデルとShopモデルはOrderモデルをthroughして多対多の関係
・Orderモデルは、その注文の状態を表す「status:string」カラムを持つ。
・その「status」は、「"not_read", "review", "accept", "reject"」という値のいずれかを持つ

ここまでを、以下のコードで記述しています。

Ruby

1#モデル 2class User < ActiveRecord::Base 3 has_many :shop, through:orders 4 has_many :orders, dependent: :destroy 5end 6 7class Shop < ActiveRecord::Base 8 has_many :users, through: :orders 9 has_many :orders, dependent: :destroy 10end 11 12class Order < ActiveRecord::Base 13 belongs_to :shop 14 belongs_to :user 15 16 ORDER_STATUS = %w(not_read review accept reject).freeze 17 validates :order_status, inclusion: { in: ORDER_STATUS } 18 19 class << self 20 def order_status_text(status) 21 I18n.t("activerecord.attributes.order.status_#{status}") 22 end 23 end 24end

Ruby

1#コントローラー 2class OrdersController < ApplicationController 3 4 def new 5 @shop = Shop.find(params[:id]) 6 @order = Order.new 7 end 8 9 def create 10 @order = Order.new( order_params ) 11 12 respond_to do |format| 13 if @order.save 14 format.html { redirect_to current_shop, notice: '注文が完了しました' } 15 format.json { render :show, status: :created, location: @order } 16 else 17 format.html { render :new } 18 format.json { render json: @order.errors, status: :unprocessable_entity } 19 end 20 end 21 end 22 23end

ビューでは、注文内容に加え、:shop_idと:user_idをhidden_fieldでcreateに渡しています。

ここまでで、とりあえずuserはshopに注文を出来るようになったのですが、ここから先の仕様の実装方法にわからない箇所があります。

1.userがshopに対して持つorder.statusは、デフォルトでは「not_read」
2.shopがshowメソッドでorderを確認した時、order.statusは「review」に変更
3.reviewに変更した時間を取得し、そこから10日が経ったら自動的にorder.statusを「reject」に変更
4.order.statusが「reject」もしくは「accept」になってから3日後に、再度userは同じshopにorderできるようになる

1,2については実装しているのですが、3,4の実装方法がわかりません。
3では値を自動で変更する必要があり、4では値が「rejectかaccept」に変更されてからの時間を取得してバリデーションを組む必要があるのかな、とは考えているのですが、その具体的な記述方法に頭を抱えています。

orderの削除については過去のorder全てをデータベースには残したいため、orderを削除するのではなく「reject」というフラグを持たせて削除したように見せているつもりです。

大変お手数ですが、ご回答いただけますと助かりますm(__)m

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

reviewに変更した時間を取得し、そこから10日が経ったら自動的にorder.statusを「reject」に変更

これの実装方法はいくつかあります。

  1. DelayedJobやSidekiqを使う方法
    • 一番使いやすいですが、環境のセットアップがすこし面倒です
  2. cronを使う方法
    • 一番シンプルですが、 cron 経由での面倒さとかあるので……
  3. ユーザがアクセスしてきたときに処理する方法
    • 仮に10日後に変化すべきデータであっても、アクセスが無い限りは変更する必要がないので、ユーザがアクセスしてきたタイミングで書き換え処理をすればよいです
    • 処理の書き方は面倒ですが、完全にWebサーバーだけで完結するところがメリットです

4では値が「rejectかaccept」に変更されてからの時間を取得してバリデーションを組む必要があるのかな

statusをrejectに変えるときに

lang

1order.update(status: "reject", rejected_at: Time.current)

とできるようなrejected_atフィールドを作成して使えばよいと思います。

投稿2015/08/04 00:27

hello-world

総合スコア1342

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jusco

2015/08/04 07:42

具体的なご回答をいただき、ありがとうございます! 今回は、バックグランドでデータを変更して、変更すべき期限の数日前に通知メールを送る処理などが必要だったため、Wheneverを使用してcronっぽい(?)実装をしました。 rejected_atの件についても触れてくださっていたので、ベストアンサーとさせていただきました。 いつもありがとうございます!
guest

0

通知する必要が無ければ、cronもwheneverも使う必要はないでしょう。

orderにupdate_at属性でも作っておいて、

Ruby

1# shop側でorderを閲覧するメソッドで事前判定 2if order.status == 'review' && order.updated_at < 10.days.from_now 3 order.status = 'reject' 4 order.update_at = order.update_at + 10.days 5 order.save 6end 7 8# userが新しくorderするメソッドで事前判定 9newest_order = user.orders.order(Order.arel_table[:update_at].desc).first 10order_available = false 11if (newest_order.status == "review" && newest_order.update_at < 10.days.from_now) 12 newest_order.status = 'reject' 13 order.update_at = order.update_at + 10.days 14 newest_order.save 15 if (newest_order.update_at < 3.days.from_now) 16 oder_available = true 17 end 18elsif (newest_order.status == "accept" || newest_order.status == "reject") && 19 newest_order.update_at < 3.days.from_now 20 order_available = true 21end 22unless oder_available 23 flash[:error] = "まだ注文できません。" 24end 25 26## oder_update_atは自動で更新されないので、ステータス変更のたびに日付を更新する必要はある

こんな感じでいいのでは?

order.satausが変更するタイミングで、メールを送信するなどの操作を行いたいのであれば、
wheneverあたりを使うのが適切でしょうが、そうでなければアクセスしたときの判定で十分でしょう。

投稿2015/08/04 02:20

編集2015/08/04 02:27
rifuch

総合スコア1901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jusco

2015/08/04 07:43

今回は、まさしくstatusが変化するタイミングでメール送信が必要だったため、wheneverを利用しての実装を選びました! そういったケース以外の対応として、覚えておきたいと思います。 いつもご回答頂き、ありがとうございます!
guest

0

railsで定期的なバッチ処理はWheneverで実行可能です。
http://qiita.com/yumiyon/items/388fbb84450f49a6ab0d

投稿2015/08/03 14:09

chiku_

総合スコア1464

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jusco

2015/08/04 07:40

ご回答ありがとうございました! リンク先も参考にさせていただきました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問