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

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

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

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

Ruby on Rails

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

Ruby on Rails 4

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

Q&A

3回答

2127閲覧

Rubyコードの書き方をスマートにしたい

kenny_sayama

総合スコア1036

Ruby

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

Ruby on Rails

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

Ruby on Rails 4

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

0グッド

0クリップ

投稿2016/09/28 14:48

編集2022/01/12 10:55

###前提・実現したいこと
以下のコードをスマートにしたいのですが、何かいい方法はないでしょうか?

###該当のソースコード

Ruby

1@user = params[:id] 2 3# 今月の月初めと月末までの投稿数を取得 4this_month = Time.now.at_beginning_of_month 5to_this_month = this_month + 1.month 6@this_month = Post.where(user_id: @user.id, created_at: this_month...to_this_month).count 7 8# 先月の投稿数 9last_month = this_month.last_month 10to_last_month = last_month + 1.month 11@last_month = Post.where(user_id: @user.id, created_at: last_month...to_last_month).count 12 13# 先々月の投稿数 14month_before_last = this_month.month_ago(2) 15to_month_before_last = month_before_last + 1.month 16@last_month = Post.where(user_id: @user.id, created_at: last_month...to_last_month).count

もっとすっきりかけると思うのですが、いい案が思いつかず、お力を貸していただきたいです

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2016/09/28 16:07

上記のコードは月末日の投稿を含めないコードになっていますが正しいですか?
kenny_sayama

2016/09/28 23:56

ご指摘の通りでしたので、修正しました!
guest

回答3

0

やりたいことは”月毎の投稿数を取得する”ということですよね。
どれも期間としては1ヶ月ごとで、+ 1.month は共通になっていますね。
なのでそれもメソッドに入れて、post_count_per_monthとしたらどうでしょうか?
月毎の投稿数を取得するという意図が伝わりやすくなるかと思います。

ruby

1@user = User.find(params[:id]) 2 3# 今月の月初めと月末までの投稿数を取得 4this_month = Time.now.at_beginning_of_month 5@this_month = post_count_per_month(@user.id, this_month) 6 7# 先月の投稿数 8@last_month = post_count_per_month(@user.id, this_month.last_month) 9 10# 先々月の投稿数 11@last_month = post_count_per_month(@user.id, this_month.month_ago(2))

ruby

1def post_count_per_month(user_id, month) 2 Post.where(user_id: user_id, created_at: month...(month + 1.month)).count 3end

投稿2016/10/11 15:48

編集2016/10/11 15:51
cameluby

総合スコア891

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

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

0

before_action :current_user, only: [:index] before_action :last_3_months_post_count, only: [:index] private def current_user @user = params[:id] end def last_3_months_post_count # * 今月の月初めと月末までの投稿数を取得 # * 先月の投稿数 # * 先々月の投稿数 @monthly_post_counts = [ monthly_post_count((Time.current)...(1.month.from_now)), monthly_post_count((1.month.ago)..(2.month.ago)), monthly_post_count((2.month.ago)..(3.month.ago)) ] end def monthly_post_count(duration) Post.where(user_id: @user.id, created_at: duration).count end
  • before_action を書くことで、アクション本体の記述量を削減
  • モデルへの問い合わせ部分は処理が共通しているので、メソッドに書き出す

View 側でどのように表示しているのかが気になりますが、似たような場所に書き出すのであれば、上のように配列にしてしまってもよいかもしれません

「3ヶ月毎」と探す範囲が固定であれば、この処理自体をモデルのメソッドや、 scope メソッドとして移行してしまってもよいかもしれません

ruby

1@monthly_post_counts = Post.last_3_months_post_count

(※雰囲気をお伝えしたかったので、実際の動作についてはご容赦ください)

Rails は数多くの様々なメソッドを用意してくれています
(私含め)Rails の機能を活用した書き方をしていきたいですね

簡単に調べてみましたが、何か参考になれば幸いです

Links

投稿2016/10/08 11:32

gouf

総合スコア2321

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

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

0

一応実装の時に考えることは
rangeオブジェクトは
ご存知かもしれませんが,

.2個で等号含む
.3個で不等号のみ

を考え,実際にサーバにどのようなqueryが投げられているか確認すると,無駄を削減できると思います。
また,共通の処理を関数に切り出し,いいかもしれません。私は以下のように特定の月次ではなく任意の区間を指定できるような実装にして汎用性を高くします。
もし月次の定義がずれていた場合は,適宣補完していただけると幸いです。

ruby

1 2def main_action 3 @this_month,@last_month,@before_last_month = fetch_during_month_data 4end 5 6private 7 8def fetch_during_month_data(start_month=Date.today.month-2,end_month=Date.today.month,year=Date.today.year) 9 end_month.downto(start_month).map do |target_month| 10 current_month = Date.new(year,target_month) 11 fetch_monthly_data(current_month...current_month.next_month) 12 end 13end 14 15def fetch_monthly_data(range) 16 User.where(user_id: @user.id, created_at:range).count 17end

もしくはfetch_monthly_data(range)はまとめてしまって

ruby

1 2def main_action 3 @this_month,@last_month,@before_last_month = fetch_during_month_data 4end 5 6private 7 8def fetch_during_month_data(start_month=Date.today.month-2,end_month=Date.today.month,year=Date.today.year) 9 end_month.downto(start_month).map do |target_month| 10 current_month = Date.new(year,target_month) 11 range = current_month...current_month.next_month 12 User.where(user_id: @user.id, created_at:range).count 13 end 14end 15

とします。

追記

上記コードは,年次ごとにはわかりやすいのですが,年をまたげないので年をまたぐ必要がある場合にはfetch_during_month_dataを以下のように修正します。

ruby

1def fetch_during_month_data(end_month=Date.today.month,back_months = 2 ,year=Date.today.year) 2 current_month = Date.new(year,end_month) 3 (0..back_months).map do |back| 4 current_month = current_month.months_ago(back) 5 range = current_month...current_month.next_month 6 User.where(user_id: @user.id, created_at:range).count 7 end 8end

期間指定したい場合は,

ruby

1def main_action 2 @this_month,@last_month,@before_last_month = fetch_during_month_data 3end 4 5private 6 7def fetch_during_month_data(start_month=Date.today.months_ago(2),end_month=Date.today) 8 back_months = (end_month.year - start_month.year)*12 - start_month.month + end_month.month 9 (0..back_months).map do |back| 10 current_month = current_month.months_ago(back) 11 range = current_month...current_month.next_month 12 User.where(user_id: @user.id, created_at:range).count 13 end 14end 15

とすることでできます。

投稿2016/09/28 17:33

編集2016/09/28 18:56
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問