diff --git a/app/controllers/dojos_controller.rb b/app/controllers/dojos_controller.rb index a9f7f9f78..bd20e735c 100644 --- a/app/controllers/dojos_controller.rb +++ b/app/controllers/dojos_controller.rb @@ -28,7 +28,7 @@ def index end @dojos = [] - dojos_scope.includes(:prefecture).order(is_active: :desc, order: :asc).each do |dojo| + dojos_scope.includes(:prefecture).order_by_active_status.order(order: :asc).each do |dojo| # 年が選択されている場合は、その年末時点でのアクティブ状態を判定 # 選択されていない場合は、現在の is_active を使用 is_active_at_selected_time = if @selected_year @@ -36,7 +36,7 @@ def index # inactivated_at が nil(まだアクティブ)または選択年より後に非アクティブ化 dojo.inactivated_at.nil? || dojo.inactivated_at > Time.zone.local(@selected_year).end_of_year else - dojo.is_active + dojo.active? end @dojos << { diff --git a/app/models/dojo.rb b/app/models/dojo.rb index 2e7a853ac..6f682df67 100644 --- a/app/models/dojo.rb +++ b/app/models/dojo.rb @@ -14,8 +14,13 @@ class Dojo < ApplicationRecord before_save { self.email = self.email.downcase } scope :default_order, -> { order(prefecture_id: :asc, order: :asc) } - scope :active, -> { where(is_active: true ) } - scope :inactive, -> { where(is_active: false) } + scope :active, -> { where(inactivated_at: nil) } + scope :inactive, -> { where.not(inactivated_at: nil) } + + # ソート用スコープ: アクティブな道場を先に表示 + scope :order_by_active_status, -> { + order(Arel.sql('CASE WHEN inactivated_at IS NULL THEN 0 ELSE 1 END')) + } # 新しいスコープ: 特定の日時点でアクティブだったDojoを取得 scope :active_at, ->(date) { @@ -103,27 +108,10 @@ def reactivate! end end - update!( - is_active: true, - inactivated_at: nil - ) + update!(inactivated_at: nil) end - # is_activeとinactivated_atの同期(移行期間中) - before_save :sync_active_status - private - - def sync_active_status - if is_active_changed? - if is_active == false && inactivated_at.nil? - self.inactivated_at = Time.current - elsif is_active == true && inactivated_at.present? - # is_activeがtrueに変更された場合、inactivated_atをnilに - self.inactivated_at = nil - end - end - end # Now 6+ tags are available since this PR: # https://github.com/coderdojo-japan/coderdojo.jp/pull/1697 diff --git a/db/dojos.yaml b/db/dojos.yaml index 25043a9a3..ac79fe5c6 100644 --- a/db/dojos.yaml +++ b/db/dojos.yaml @@ -15,7 +15,6 @@ - 電子工作 - id: 104 order: '011002' - is_active: false inactivated_at: '2023-09-12 20:25:52' created_at: '2016-09-26' name: 札幌東 @@ -31,7 +30,6 @@ - Unity - id: 253 order: '012050' - is_active: false inactivated_at: '2024-12-28 23:41:50' note: https://www.facebook.com/search/top/?q=coderdojo室蘭 created_at: '2020-09-10' @@ -92,7 +90,6 @@ - JavaScript - id: 259 order: '032093' - is_active: false inactivated_at: '2023-01-08 15:29:52' created_at: '2020-12-15' name: 一関平泉 @@ -108,7 +105,6 @@ - Webサイト - id: 201 order: '032026' - is_active: false inactivated_at: '2022-03-16 16:42:10' created_at: '2019-02-14' name: 宮古 @@ -144,7 +140,6 @@ - ラズベリーパイ - id: 107 order: '032069' - is_active: false inactivated_at: '2022-06-08 01:58:59' created_at: '2017-06-20' name: きたかみ @@ -168,7 +163,6 @@ - Scratch - id: 90 order: '041009' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2017-07-01' name: 愛子 @@ -196,7 +190,6 @@ - BASIC - id: 85 order: '042072' - is_active: false inactivated_at: '2019-04-28 10:25:26' created_at: '2017-03-27' name: 名取 @@ -210,7 +203,6 @@ - ゲーム - id: 4 order: '042129' - is_active: false inactivated_at: '2023-10-26 14:06:02' created_at: '2016-04-25' name: 登米 @@ -240,7 +232,6 @@ - MakeyMakey - id: 59 order: '044458' - is_active: false inactivated_at: '2022-03-16 16:58:18' created_at: '2016-10-06' name: 中新田 @@ -252,7 +243,6 @@ - Scratch - id: 75 order: '052019' - is_active: false inactivated_at: '2025-03-19 17:51:05' note: Last session was 2023-05-06 created_at: '2017-04-03' @@ -269,7 +259,6 @@ - 3Dプリンタ - id: 139 order: '052035' - is_active: false inactivated_at: '2022-03-16 16:58:18' created_at: '2018-03-27' name: 増田 @@ -282,7 +271,6 @@ - Minecraft - id: 74 order: '062014' - is_active: false inactivated_at: '2023-01-08 14:33:49' created_at: '2017-03-28' name: 山形@2017 @@ -337,7 +325,6 @@ - Minecraft - id: 215 order: '063410' - is_active: false inactivated_at: '2020-01-04 19:14:14' created_at: '2019-04-24' name: 大石田@PCチャレンジ倶楽部 @@ -479,7 +466,6 @@ - IslayTouch - id: 203 order: '082210' - is_active: false inactivated_at: '2023-09-18 14:08:28' created_at: '2019-02-23' name: 六ツ野 @@ -503,7 +489,6 @@ - Islay - id: 222 order: '082015' - is_active: false inactivated_at: '2023-10-26 14:20:23' created_at: '2019-07-23' name: 三の丸 @@ -516,7 +501,6 @@ - C言語 - id: 176 order: '082023' - is_active: false inactivated_at: '2023-02-02 13:27:14' created_at: '2018-10-08' name: 日立 @@ -542,7 +526,6 @@ - 電子工作 - id: 246 order: '092011' - is_active: false inactivated_at: '2023-10-26 14:17:35' created_at: '2020-03-11' name: 宇都宮 @@ -570,7 +553,6 @@ - Webサイト - id: 242 order: '092100' - is_active: false inactivated_at: '2023-10-26 15:31:15' created_at: '2020-02-20' name: おおたわら @@ -626,7 +608,6 @@ - ゲーム - id: 180 order: '102075' - is_active: false inactivated_at: '2019-04-29 14:41:31' created_at: '2018-08-08' name: 館林 @@ -666,7 +647,6 @@ - Unity - id: 12 order: '112089' - is_active: false inactivated_at: '2023-01-08 15:08:39' created_at: '2015-12-01' name: 所沢 @@ -678,7 +658,6 @@ - Scratch - id: 77 order: '112089' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2017-03-14' name: 小手指 @@ -690,7 +669,6 @@ - Scratch - id: 287 order: '112089' - is_active: false inactivated_at: '2025-03-19 18:09:38' note: Last session was 2023年8月27日 created_at: '2022-09-20' @@ -708,7 +686,6 @@ - id: 11 order: '112097' note: Re-activated @ 2024-08-19 https://www.facebook.com/groups/coderdojo.jp/posts/8010099192436743/ - is_active: true created_at: '2015-05-13' name: 飯能 prefecture_id: 11 @@ -749,7 +726,6 @@ - Unity - id: 238 order: '112305' - is_active: false inactivated_at: '2023-10-26 14:47:39' created_at: '2020-02-03' name: 新座志木 @@ -761,7 +737,6 @@ - Scratch - id: 22 order: '121002' - is_active: false inactivated_at: '2021-04-06 15:33:38' created_at: '2013-07-30' name: 千葉 @@ -778,7 +753,6 @@ - id: 25 order: '121002' created_at: '2016-04-27' - is_active: false inactivated_at: '2025-03-01 14:24:27' note: Inactived at 2025-03-01 name: 若葉みつわ台 @@ -888,7 +862,6 @@ - Scratch - id: 20 order: '122084' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2016-11-08' name: 野田 @@ -900,7 +873,6 @@ - Scratch - id: 283 order: '122084' - is_active: false inactivated_at: '2023-10-26 15:53:42' created_at: '2022-04-21' name: 野田 @@ -923,7 +895,6 @@ - Scratch - id: 125 order: '122173' - is_active: false inactivated_at: '2023-09-18 13:56:39' created_at: '2018-01-27' name: 柏沼南 @@ -967,7 +938,6 @@ - micro:bit - id: 284 order: '122211' - is_active: false inactivated_at: '2025-03-19 17:52:34' note: Last session was 2023-06-25 created_at: '2022-06-17' @@ -1011,7 +981,6 @@ - Ruby - id: 152 order: '122301' - is_active: false inactivated_at: '2022-03-16 17:29:45' created_at: '2018-06-30' name: やちまた @@ -1023,7 +992,6 @@ - Scratch - id: 219 order: '122319' - is_active: false inactivated_at: '2023-10-26 15:25:10' created_at: '2019-06-26' name: 印西 @@ -1038,7 +1006,6 @@ - Minecraft - id: 157 order: '122302' - is_active: false inactivated_at: '2021-06-16 14:16:45' created_at: '2018-11-25' name: 酒々井 @@ -1052,7 +1019,6 @@ - id: 158 order: '122303' note: 2024-09-21 https://x.com/KEITAROinNRT/status/1837328724599189598 - is_active: true created_at: '2018-11-17' name: 成田 prefecture_id: 12 @@ -1063,7 +1029,6 @@ - Scratch - id: 121 order: '131016' - is_active: false inactivated_at: '2024-07-30 23:38:59' note: Last session was 2022-10-22 created_at: '2017-11-28' @@ -1078,7 +1043,6 @@ - micro:bit - id: 97 order: '131016' - is_active: false inactivated_at: '2023-08-24 19:45:08' created_at: '2017-08-16' name: 末広町 @@ -1204,7 +1168,6 @@ - Minecraft - id: 58 order: '131041' - is_active: false inactivated_at: '2020-08-20 15:15:33' created_at: '2017-09-26' name: 高田馬場 @@ -1218,7 +1181,6 @@ - Ruby - id: 69 order: '131041' - is_active: false inactivated_at: '2022-03-16 16:52:14' created_at: '2017-01-23' name: 西新宿 @@ -1244,7 +1206,6 @@ - 電子工作 - id: 302 order: '131059' - is_active: true note: Last session was 2023-08-29. Re-activated at 2025-06-22. https://x.com/Coderdojo_Hongo/status/1927880002046971943 created_at: 2023-06-08 name: ほんごう @@ -1273,7 +1234,6 @@ - 映像制作 - id: 185 order: '131091' - is_active: false inactivated_at: '2023-10-15 11:39:02' created_at: '2018-11-20' name: 五反田 @@ -1288,7 +1248,6 @@ - Swift - id: 313 order: '131113' - is_active: false inactivated_at: '2024-06-18 11:45:59' created_at: '2023-11-07' name: 平和島 @@ -1311,7 +1270,6 @@ - Webサイト - id: 17 order: '131121' - is_active: false inactivated_at: '2022-03-16 16:52:14' created_at: '2012-03-12' name: 下北沢 @@ -1350,7 +1308,6 @@ - micro:bit - id: 19 order: '131130' - is_active: false inactivated_at: '2025-05-26 15:55:51' note: Re-activated@24-04-01. Re-deactivated@25-05-26 with approval from the champion. created_at: '2020-01-30' @@ -1382,7 +1339,6 @@ - 刺繍ミシン - id: 15 order: '131148' - is_active: false inactivated_at: '2023-10-26 14:29:00' created_at: '2016-07-20' name: 中野 @@ -1397,7 +1353,6 @@ - Arduino - id: 16 order: '131156' - is_active: false inactivated_at: '2022-03-16 17:29:45' created_at: '2016-09-09' name: すぎなみ @@ -1436,7 +1391,6 @@ - Scratch - id: 231 order: '131199' - is_active: false inactivated_at: '2023-10-26 14:37:52' created_at: '2019-10-30' name: 板橋@桜川 @@ -1452,7 +1406,6 @@ - micro:bit - id: 233 order: '131211' - is_active: false inactivated_at: '2025-03-19 17:46:09' note: Last session was 2023-10-29 as of 2024-07-30 created_at: '2019-11-19' @@ -1465,7 +1418,6 @@ - Scratch - id: 14 order: '132012' - is_active: false inactivated_at: '2023-10-26 15:09:44' created_at: '2015-06-22' name: 八王子 @@ -1492,7 +1444,6 @@ - Arduino - id: 221 order: '132021' - is_active: false inactivated_at: '2023-10-26 14:30:55' created_at: '2019-07-08' name: たまみら @@ -1521,7 +1472,6 @@ - Java - id: 174 order: '132047' - is_active: false inactivated_at: '2022-03-16 17:34:16' created_at: '2018-10-05' name: 三鷹 @@ -1547,7 +1497,6 @@ - RPA - id: 228 order: '132071' - is_active: false inactivated_at: '2023-10-26 15:26:07' created_at: '2019-10-11' name: 昭島 @@ -1580,7 +1529,6 @@ - Python - id: 212 order: '132080' - is_active: false inactivated_at: '2022-03-16 17:34:16' created_at: '2019-06-10' name: 調布@電気通信大学 @@ -1635,7 +1583,6 @@ - Arduino - id: 275 order: '132152' - is_active: false inactivated_at: '2022-03-16 17:34:16' created_at: '2021-09-22' name: 国立 @@ -1675,7 +1622,6 @@ - micro:bit - id: 204 order: '132233' - is_active: false inactivated_at: '2023-10-26 15:19:19' created_at: '2019-02-26' name: 武蔵村山 @@ -1703,7 +1649,6 @@ - micro:bit - id: 70 order: '141020' - is_active: false inactivated_at: '2022-03-16 17:40:26' created_at: '2017-01-30' name: 横浜 @@ -1715,7 +1660,6 @@ - Scratch - id: 126 order: '141038' - is_active: false inactivated_at: '2024-06-24 11:52:16' created_at: '2018-02-02' name: 戸部 @@ -1730,7 +1674,6 @@ - Hour of Code - id: 137 order: '141062' - is_active: false inactivated_at: '2022-03-16 17:47:40' created_at: '2018-03-24' name: 保土ヶ谷 @@ -1743,7 +1686,6 @@ - micro:bit - id: 68 order: '141097' - is_active: false inactivated_at: '2022-03-16 17:47:40' created_at: '2017-01-09' name: 新羽 @@ -1756,7 +1698,6 @@ - Hour of Code - id: 208 order: '141097' - is_active: false inactivated_at: '2023-10-26 14:45:37' created_at: '2019-03-08' name: 小机 @@ -1785,7 +1726,6 @@ - Python - id: 76 order: '141135' - is_active: false inactivated_at: '2023-10-26 14:59:54' created_at: '2017-04-03' name: 長津田 @@ -1799,7 +1739,6 @@ - Hour of Code - id: 154 order: '141135' - is_active: false inactivated_at: '2022-03-16 17:52:34' created_at: '2017-04-03' name: 鴨居 @@ -1826,7 +1765,6 @@ - micro:bit - id: 179 order: '141186' - is_active: false inactivated_at: '2025-03-19 18:07:54' note: Last session was 2023-08-19 created_at: '2018-08-15' @@ -1852,7 +1790,6 @@ - Scratch - id: 210 order: '141305' - is_active: false inactivated_at: '2024-03-30 19:51:55' created_at: '2019-05-05' name: 久地 @@ -1881,7 +1818,6 @@ - ドローン - id: 138 order: '142042' - is_active: false inactivated_at: '2019-04-29 14:41:31' created_at: '2018-03-25' name: 鎌倉 @@ -1909,7 +1845,6 @@ - Minecraft - id: 26 order: '142051' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2016-12-14' name: 藤沢 @@ -1936,7 +1871,6 @@ - Markdown - id: 199 order: '142077' - is_active: false inactivated_at: '2022-03-16 17:55:10' created_at: '2019-02-06' name: 茅ヶ崎 @@ -1950,7 +1884,6 @@ - IchigoJam - id: 247 order: '142131' - is_active: false inactivated_at: '2023-03-15 09:09:32' created_at: '2020-05-07' name: 中央林間 @@ -1976,7 +1909,6 @@ - Webサイト - id: 91 order: '142158' - is_active: false inactivated_at: '2022-03-16 18:02:33' created_at: '2017-06-26' name: 海老名 @@ -1998,7 +1930,6 @@ - Scratch - id: 5 order: '151009' - is_active: false inactivated_at: '2022-03-16 18:02:33' created_at: '2015-09-16' name: 新潟西 @@ -2142,7 +2073,6 @@ - HackforPlay - id: 28 order: '182010' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2013-08-14' name: 福井 @@ -2155,7 +2085,6 @@ - Webサイト - id: 88 order: '192015' - is_active: true note: Re-activated @ 2024-11-15 https://www.facebook.com/share/p/1a51trhzQo/ created_at: '2017-05-29' name: 甲府 @@ -2169,7 +2098,6 @@ - 電子工作 - id: 195 order: '192074' - is_active: false inactivated_at: '2023-09-12 20:23:06' created_at: '2019-02-03' name: 韮崎 @@ -2185,7 +2113,6 @@ - Processing - id: 196 order: '192091' - is_active: false inactivated_at: '2023-02-02 13:29:36' created_at: '2019-02-03' name: 北杜 @@ -2201,7 +2128,6 @@ - Processing - id: 133 order: '192104' - is_active: false inactivated_at: '2022-03-16 18:11:25' created_at: '2018-03-02' name: 甲斐竜王 @@ -2243,7 +2169,6 @@ - LEGO - id: 232 order: '202037' - is_active: false inactivated_at: '2023-10-26 14:41:11' created_at: '2019-11-10' name: 上田 @@ -2270,7 +2195,6 @@ - M5Stack - id: 94 order: '202061' - is_active: false inactivated_at: '2023-02-02 13:42:56' created_at: '2017-02-20' name: 諏訪湖 @@ -2286,7 +2210,6 @@ - LEGO - id: 237 order: '202096' - is_active: false inactivated_at: '2024-07-30 22:05:53' note: Last sesion was 2023-03-25 https://www.facebook.com/CoderDojoIna created_at: '2020-01-19' @@ -2314,7 +2237,6 @@ - Ruby - id: 87 order: '202207' - is_active: false inactivated_at: '2023-10-26 14:58:41' created_at: '2017-05-11' name: 安曇野 @@ -2356,7 +2278,6 @@ - LEGO - id: 96 order: '212211' - is_active: false inactivated_at: '2022-03-16 18:11:25' created_at: '2017-09-26' name: 海津 @@ -2380,7 +2301,6 @@ - micro:bit - id: 197 order: '212041' - is_active: false inactivated_at: '2021-09-28 10:22:53' created_at: '2019-02-03' name: 東濃 @@ -2508,7 +2428,6 @@ - ラズベリーパイ - id: 214 order: '232033' - is_active: false inactivated_at: '2022-03-16 18:28:38' created_at: '2019-05-18' name: 一宮 @@ -2579,7 +2498,6 @@ - Viscuit - id: 84 order: '232211' - is_active: false inactivated_at: '2019-04-28 10:25:26' created_at: '2017-05-16' name: 新城 @@ -2655,7 +2573,6 @@ - IchigoJam - id: 33 order: '234249' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2016-08-12' name: 大治 @@ -2667,7 +2584,6 @@ - Scratch - id: 255 order: '242021' - is_active: false inactivated_at: '2023-10-26 15:27:23' created_at: '2020-11-02' name: 四日市 @@ -2681,7 +2597,6 @@ - Minecraft - id: 62 order: '242039' - is_active: true note: 2025-03-16 https://www.instagram.com/p/DG990t1PjEk/?img_index=1 created_at: '2016-12-22' name: 伊勢 @@ -2696,7 +2611,6 @@ - LabVIEW - id: 37 order: '252018' - is_active: false inactivated_at: '2022-03-16 18:28:38' created_at: '2015-09-16' name: 大津 @@ -2708,7 +2622,6 @@ - Scratch - id: 39 order: '261009' - is_active: false inactivated_at: '2023-01-08 14:39:30' created_at: '2016-03-01' name: 京都伏見 @@ -2724,7 +2637,6 @@ is_private: true - id: 240 order: '261009' - is_active: true created_at: '2020-02-09' name: 京都四条 prefecture_id: 26 @@ -2758,7 +2670,6 @@ - Scratch - id: 250 order: '262129' - is_active: false inactivated_at: '2023-10-26 15:29:45' created_at: '2020-06-27' name: 京丹後 @@ -2801,7 +2712,6 @@ - 電子工作 - id: 43 order: '271004' - is_active: false inactivated_at: '2019-04-28 10:25:26' created_at: '2016-09-27' name: なんば @@ -2830,7 +2740,6 @@ - 電子工作 - id: 116 order: '271004' - is_active: false inactivated_at: '2022-03-16 18:28:38' created_at: '2017-11-02' name: 阿倍野 @@ -2844,7 +2753,6 @@ - Minecraft - id: 45 order: '271004' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2016-07-13' name: 西成 @@ -2868,7 +2776,6 @@ - Webサイト - id: 266 order: '271217' - is_active: false inactivated_at: '2023-10-26 14:33:00' created_at: '2021-04-25' name: 東住吉 @@ -2993,7 +2900,6 @@ - アプリ開発 - id: 256 order: '272116' - is_active: false inactivated_at: '2025-03-19 17:48:25' note: Last session was 2023-06-24 created_at: '2020-11-07' @@ -3022,7 +2928,6 @@ - Python - id: 135 order: '272183' - is_active: false inactivated_at: '2023-10-15 14:01:23' created_at: '2018-03-13' name: 大東 @@ -3036,7 +2941,6 @@ - ラズベリーパイ - id: 108 order: '272205' - is_active: false inactivated_at: '2023-10-26 16:00:22' created_at: '2017-09-06' name: みのお @@ -3049,7 +2953,6 @@ - JavaScript - id: 271 order: '272213' - is_active: false inactivated_at: '2021-07-19 18:19:37' created_at: '2021-06-20' name: 柏原 @@ -3065,7 +2968,6 @@ - Arduino - id: 41 order: '272272' - is_active: false inactivated_at: '2022-03-16 18:33:31' created_at: '2016-09-01' name: 東大阪 @@ -3079,7 +2981,6 @@ - Android - id: 101 order: '272124' - is_active: false inactivated_at: '2022-03-16 18:33:31' created_at: '2017-08-03' name: 八尾 @@ -3119,7 +3020,6 @@ - Android - id: 264 order: '272264' - is_active: false inactivated_at: '2021-07-19 18:19:37' created_at: '2021-02-28' name: 藤井寺 @@ -3173,7 +3073,6 @@ - ラズベリーパイ - id: 119 order: '281069' - is_active: false inactivated_at: '2023-10-15 15:48:53' created_at: '2017-11-08' name: 西神戸 @@ -3188,7 +3087,6 @@ - Java - id: 67 order: '281093' - is_active: false inactivated_at: '2019-04-28 10:25:26' created_at: '2016-09-12' name: 北神戸 @@ -3229,7 +3127,6 @@ - Java - id: 50 order: '282014' - is_active: false inactivated_at: '2023-10-26 15:11:42' created_at: '2016-03-22' name: 姫路 @@ -3243,7 +3140,6 @@ - Webサイト - id: 49 order: '282031' - is_active: true note: Re-activated since 2025-08-02 https://coderdojo-akashi.connpass.com/event/362346/ created_at: '2016-04-04' name: 明石 @@ -3285,7 +3181,6 @@ - Python - id: 220 order: '282065' - is_active: false inactivated_at: '2022-03-16 16:42:10' created_at: '2019-07-07' name: あしや @@ -3299,7 +3194,6 @@ - Webサイト - id: 230 order: '282154' - is_active: false inactivated_at: '2023-02-02 13:25:48' created_at: '2019-11-01' name: みき @@ -3388,7 +3282,6 @@ - Webサイト - id: 236 order: '292095' - is_active: false inactivated_at: '2022-03-16 18:44:37' created_at: '2020-01-11' name: 法隆寺 @@ -3411,7 +3304,6 @@ - micro:bit - id: 128 order: '293431' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2018-02-18' name: 三郷 @@ -3423,7 +3315,6 @@ - Scratch - id: 169 order: '293636' - is_active: false inactivated_at: '2019-06-08 02:14:10' created_at: '2018-07-31' name: 明日香 @@ -3438,7 +3329,6 @@ - Webサイト - id: 177 order: '293636' - is_active: false inactivated_at: '2020-12-29 16:35:44' created_at: '2018-07-31' name: 田原本 @@ -3487,7 +3377,6 @@ - ラズベリーパイ - id: 38 order: '302074' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2012-11-08' name: 熊野 @@ -3501,7 +3390,6 @@ - アプリ - id: 115 order: '313866' - is_active: false inactivated_at: '2019-12-17 10:19:31' created_at: '2017-08-16' name: 大山 @@ -3547,7 +3435,6 @@ - micro:bit - id: 211 order: '322059' - is_active: false inactivated_at: '2020-07-31 14:01:02' created_at: '2019-06-11' name: 石見@Takuno @@ -3562,7 +3449,6 @@ - ラズベリーパイ - id: 225 order: '320225' - is_active: false inactivated_at: '2023-01-08 14:26:58' created_at: '2019-09-06' name: 浜田 @@ -3576,7 +3462,6 @@ - Ruby - id: 245 order: '325015' - is_active: true note: 2024-06-23 https://coderdojo-tsuwano.connpass.com/event/322734/ created_at: '2020-03-10' name: 津和野 @@ -3592,7 +3477,6 @@ - ラズベリーパイ - id: 78 order: '325058' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2017-03-10' name: 吉賀 @@ -3660,7 +3544,6 @@ - 電子工作 - id: 258 order: '332054' - is_active: false inactivated_at: '2022-03-16 18:52:21' created_at: '2020-12-07' name: 笠岡 @@ -3688,7 +3571,6 @@ - Unity - id: 53 order: '341002' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2016-09-29' name: 五日市 @@ -3701,7 +3583,6 @@ - micro:bit - id: 141 order: '342025' - is_active: false inactivated_at: '2023-01-08 15:16:29' created_at: '2018-04-11' name: 呉 @@ -3714,7 +3595,6 @@ - micro:bit - id: 51 order: '342076' - is_active: false inactivated_at: '2019-04-27 15:50:33' created_at: '2016-06-01' name: 福山 @@ -3749,7 +3629,6 @@ - micro:bit - id: 192 order: '352021' - is_active: false inactivated_at: '2024-07-30 23:37:29' note: Last session was 2022-11-19 created_at: '2019-01-14' @@ -3855,7 +3734,6 @@ - OSS - id: 234 order: '372081' - is_active: false inactivated_at: '2023-10-26 14:44:26' created_at: '2019-11-26' name: 本山 @@ -3907,7 +3785,6 @@ - Unity - id: 144 order: '401005' - is_active: false inactivated_at: '2024-07-30 22:26:38' note: Last session was 2022/11/19 created_at: '2018-04-22' @@ -3934,7 +3811,6 @@ - JavaScript - id: 183 order: '401323' - is_active: false inactivated_at: '2023-10-26 14:35:47' created_at: '2018-11-03' name: 博多 @@ -4001,7 +3877,6 @@ - Webサイト - id: 172 order: '402036' - is_active: false inactivated_at: '2022-03-16 19:03:59' created_at: '2018-08-25' name: 諏訪野@ギャランドゥ @@ -4017,7 +3892,6 @@ - Mindstorms - id: 207 order: '402036' - is_active: false inactivated_at: '2023-10-26 14:39:09' created_at: '2019-03-05' name: 日吉 @@ -4033,7 +3907,6 @@ - Hour of Code - id: 229 order: '402150' - is_active: false inactivated_at: '2023-10-26 14:14:51' created_at: '2019-10-26' name: ナカマ @@ -4060,7 +3933,6 @@ - Minecraft - id: 191 order: '402214' - is_active: false inactivated_at: '2023-10-26 14:40:00' created_at: '2019-01-04' name: 太宰府 @@ -4090,7 +3962,6 @@ - Minecraft - id: 122 order: '413411' - is_active: false inactivated_at: '2022-03-16 19:09:46' created_at: '2017-12-15' name: 基山 @@ -4106,7 +3977,6 @@ - Minecraft - id: 120 order: '422011' - is_active: false inactivated_at: '2019-04-29 14:41:31' created_at: '2017-11-14' name: 長崎 @@ -4131,7 +4001,6 @@ - 電子工作 - id: 178 order: '431001' - is_active: true created_at: '2018-08-05' name: 熊本 prefecture_id: 43 @@ -4229,7 +4098,6 @@ - C-Style - id: 198 order: '472115' - is_active: false inactivated_at: '2022-03-16 16:42:10' created_at: '2019-02-03' name: コザ @@ -4321,7 +4189,6 @@ - ラズベリーパイ - id: 61 order: '473502' - is_active: false inactivated_at: '2019-11-21 00:46:23' created_at: '2012-07-09' name: 南風原 diff --git a/db/migrate/20250814115324_remove_is_active_from_dojos.rb b/db/migrate/20250814115324_remove_is_active_from_dojos.rb new file mode 100644 index 000000000..72825b563 --- /dev/null +++ b/db/migrate/20250814115324_remove_is_active_from_dojos.rb @@ -0,0 +1,8 @@ +class RemoveIsActiveFromDojos < ActiveRecord::Migration[8.0] + def change + # is_active カラムを削除 + # このカラムは inactivated_at カラムと重複していたため削除 + # Issue #1734: https://github.com/coderdojo-japan/coderdojo.jp/issues/1734 + remove_column :dojos, :is_active, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 37f4fcf2f..d16181b3e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_08_05_105233) do +ActiveRecord::Schema[8.0].define(version: 2025_08_14_115324) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" enable_extension "pg_stat_statements" @@ -36,7 +36,6 @@ t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false t.integer "prefecture_id" - t.boolean "is_active", default: true, null: false t.boolean "is_private", default: false, null: false t.integer "counter", default: 1, null: false t.text "note", default: "", null: false diff --git a/doc/plan_refactor_inactivated_at.md b/doc/plan_refactor_inactivated_at.md new file mode 100644 index 000000000..54de5dfff --- /dev/null +++ b/doc/plan_refactor_inactivated_at.md @@ -0,0 +1,183 @@ +# 超シンプル!`is_active` カラム削除計画 + +## 📋 一言で言うと + +**スコープの内部実装だけを変更して、`is_active` カラムを安全に削除する** + +## 🎯 たった1つの重要な洞察 + +``` +既存コード: Dojo.active, dojo.active? を使っている + ↓ +気づき: スコープ名を変えなければ、既存コードは変更不要! + ↓ +解決策: 内部実装だけ is_active → inactivated_at に変更 +``` + +**結果**: 99%のコードは触らずに済む! + + +## 📝 実装計画 + +### 🚀 KISS/YAGNI による究極のシンプル実装 + +#### Ultrathinking による洞察 + +**問題の本質**: `is_active` と `inactivated_at` の重複を解消したい + +**解決策**: スコープの内部実装だけを変更すれば、99%のコードは変更不要! + +### 必要な変更は「たった8箇所」だけ! + +```ruby +# 1. Dojoモデル: スコープ内部実装(2行変更) +scope :active, -> { where(inactivated_at: nil) } # is_active: true → inactivated_at: nil +scope :inactive, -> { where.not(inactivated_at: nil) } # is_active: false → inactivated_at NOT nil + +# 2. Dojoモデル: ソート用スコープを追加(新規追加) +scope :order_by_active_status, -> { + # アクティブなDojoを先に、その後に非アクティブなDojoを表示 + order(Arel.sql('CASE WHEN inactivated_at IS NULL THEN 0 ELSE 1 END')) +} + +# 3. Dojoモデル: active?メソッド(1行変更) +def active? + inactivated_at.nil? # is_active → inactivated_at.nil? +end + +# 4. Dojoモデル: sync_active_status削除(削除のみ) +# before_save :sync_active_status を削除 + +# 5. Dojoモデル: reactivate!メソッド(1行削除) +update!(inactivated_at: nil) # is_active: true を削除 + +# 6. コントローラー: ソート条件(読みやすく変更) +@dojos = Dojo.includes(:prefecture) + .order_by_active_status # 新しいスコープを使用 + .order(order: :asc) + +# 7. Rakeタスク: YAMLからの読み込み(1行削除) +# d.is_active = ... この行を削除 + +# 8. マイグレーション: カラム削除(最後に実行) +remove_column :dojos, :is_active +``` + +**変更不要なもの:** +- ✅ ビュー: 全て変更不要(`.active`スコープがそのまま動く) +- ✅ 大部分のテスト: 変更不要(インターフェースが同じ) +- ✅ CSSクラス名: 変更不要(`inactive-item`のままでOK) +- ✅ その他のコントローラー: 変更不要 + +### 実装時間: 30分で完了可能! + +この戦略により、最小限の変更で最大の効果を実現します。 + +### 実装は3つのシンプルなステップで完了! + +## Step 1: データ確認(5分) + +```ruby +# Rails console で不整合データがないか確認 +Dojo.where("(is_active = true AND inactivated_at IS NOT NULL) OR (is_active = false AND inactivated_at IS NULL)").count +# => 0 なら問題なし! +``` + +## Step 2: コード変更(10分) + +8箇所の変更を実施: + +```ruby +# 1. app/models/dojo.rb - スコープ(2行) +scope :active, -> { where(inactivated_at: nil) } +scope :inactive, -> { where.not(inactivated_at: nil) } + +# 2. app/models/dojo.rb - ソート用スコープを追加 +scope :order_by_active_status, -> { + order(Arel.sql('CASE WHEN inactivated_at IS NULL THEN 0 ELSE 1 END')) +} + +# 3. app/models/dojo.rb - active?メソッド(既に実装済み!そのまま使える) +# def active? +# inactivated_at.nil? # これは既にPR #1726で実装済み! +# end + +# 4. app/models/dojo.rb - sync_active_status削除 +# before_save :sync_active_status と private メソッドを削除 + +# 5. app/models/dojo.rb - reactivate!メソッド +# is_active: true の行を削除 + +# 6. app/controllers/dojos_controller.rb - ソート(読みやすく!) +@dojos = Dojo.includes(:prefecture) + .order_by_active_status + .order(order: :asc) + +# 7. lib/tasks/dojos.rake - is_active設定行を削除 +# d.is_active = ... の行を削除 +``` + +## Step 3: マイグレーションとテスト(15分) + +```ruby +# マイグレーション作成 +rails generate migration RemoveIsActiveFromDojos + +# マイグレーション内容(シンプル版) +def change + remove_column :dojos, :is_active, :boolean +end + +# テスト実行 +bundle exec rspec + +# デプロイ +git push && rails db:migrate +``` + +**完了!** 🎉 + +## 🎯 なぜこのアプローチが優れているか + +### KISS/YAGNI原則の実践 +- **変更箇所**: わずか8箇所(実質7箇所、1つは既に実装済み) +- **実装時間**: 30分以内 +- **リスク**: 最小限(インターフェースを変えないため) +- **可読性**: SQLをスコープに隠蔽して読みやすく +- **ロールバック**: 簡単(スコープ内部を戻すだけ) + +### Ultrathinking による洞察 +``` +表面的理解: is_activeカラムを削除したい + ↓ +深層的理解: でも既存コードを全部変更するのは大変 + ↓ +本質的洞察: スコープ名を維持すれば変更は最小限 + ↓ +究極の解決: 内部実装だけ変えれば99%のコードは触らなくて済む! +``` + +## 📝 実装チェックリスト + +- [ ] Step 1: データ整合性確認(Rails console) +- [ ] Step 2: 8箇所のコード変更 + - [ ] Dojoモデル: スコープ内部実装(2行) + - [ ] Dojoモデル: order_by_active_statusスコープ追加 + - [ ] Dojoモデル: sync_active_status削除 + - [ ] Dojoモデル: reactivate!メソッド修正 + - [ ] コントローラー: ソート条件を読みやすく変更 + - [ ] Rakeタスク: is_active行削除 +- [ ] Step 3: マイグレーション作成と実行 +- [ ] テスト実行と確認 + +## 🔗 参考 + +- Issue #1734: リファクタリング要件 +- PR #1726: `inactivated_at` カラムの追加(active?メソッド実装済み) +- PR #1732: 年次フィルタリング機能 + +--- + +**作成日**: 2025年8月14日 +**作成者**: Claude Code with Ultrathinking +**レビュー状態**: 実装前レビュー待ち \ No newline at end of file diff --git a/lib/tasks/dojos.rake b/lib/tasks/dojos.rake index 9460f9a85..638b28276 100644 --- a/lib/tasks/dojos.rake +++ b/lib/tasks/dojos.rake @@ -44,7 +44,6 @@ namespace :dojos do d.url = dojo['url'] d.prefecture_id = dojo['prefecture_id'] d.order = dojo['order'] || search_order_number_by(dojo['name']) - d.is_active = dojo['is_active'].nil? ? true : dojo['is_active'] d.is_private = dojo['is_private'].nil? ? false : dojo['is_private'] d.inactivated_at = dojo['inactivated_at'] ? Time.zone.parse(dojo['inactivated_at']) : nil d.created_at = d.new_record? ? Time.zone.now : dojo['created_at'] || d.created_at diff --git a/spec/factories/dojos.rb b/spec/factories/dojos.rb index 042b12c52..d3216c416 100644 --- a/spec/factories/dojos.rb +++ b/spec/factories/dojos.rb @@ -8,7 +8,13 @@ url { 'https://example.com' } logo { '/img/dojos/default.webp' } counter { 1 } - is_active { true } order { 131001 } + # デフォルトはアクティブ(inactivated_at: nil) + inactivated_at { nil } + + # 非アクティブなDojoを作成するためのtrait + trait :inactive do + inactivated_at { Time.current } + end end end diff --git a/spec/lib/tasks/dojos_spec.rb b/spec/lib/tasks/dojos_spec.rb index ae69f123f..67ea6dea9 100644 --- a/spec/lib/tasks/dojos_spec.rb +++ b/spec/lib/tasks/dojos_spec.rb @@ -54,7 +54,7 @@ expect(new_records.first.url).to eq('http://tinkerkids.jp/coderdojo.html') expect(new_records.first.description).to eq('毎月開催') expect(new_records.first.tags).to eq(%w(Scratch ラズベリーパイ Python JavaScript)) - expect(new_records.first.is_active).to eq(true) + expect(new_records.first.active?).to eq(true) expect(new_records.first.is_private).to eq(false) end @@ -75,20 +75,20 @@ expect(mod_record.name).to eq('dojo_1(mod)') end - context 'is_active' do + context 'inactivated_at (活性状態管理)' do let(:dojo_base) do @dojo_2.attributes.keep_if { |k,v| %w(id order name prefecture_id logo url description tags).include?(k) } end - it '指定なし ⇒ アクティブ' do + it 'inactivated_at 指定なし ⇒ アクティブ' do allow(YAML).to receive(:unsafe_load_file).and_return([ dojo_base ]) # before - @dojo_2.update_columns(is_active: false) + @dojo_2.update_columns(inactivated_at: Time.current) expect(Dojo.count).to eq(3) - expect(@dojo_2.is_active).to eq(false) + expect(@dojo_2.reload.active?).to eq(false) # exec expect(@rake[task].invoke).to be_truthy @@ -96,18 +96,19 @@ # after expect(Dojo.count).to eq(3) mod_record = Dojo.find_by(id: @dojo_2.id) - expect(mod_record.is_active).to eq(true) + expect(mod_record.active?).to eq(true) + expect(mod_record.inactivated_at).to be_nil end - it 'true 指定 ⇒ アクティブ' do + it 'inactivated_at: nil 指定 ⇒ アクティブ' do allow(YAML).to receive(:unsafe_load_file).and_return([ - dojo_base.merge('is_active' => true) + dojo_base.merge('inactivated_at' => nil) ]) # before - @dojo_2.update_columns(is_active: false) + @dojo_2.update_columns(inactivated_at: Time.current) expect(Dojo.count).to eq(3) - expect(@dojo_2.is_active).to eq(false) + expect(@dojo_2.reload.active?).to eq(false) # exec expect(@rake[task].invoke).to be_truthy @@ -115,17 +116,19 @@ # after expect(Dojo.count).to eq(3) mod_record = Dojo.find_by(id: @dojo_2.id) - expect(mod_record.is_active).to eq(true) + expect(mod_record.active?).to eq(true) + expect(mod_record.inactivated_at).to be_nil end - it 'false 指定 ⇒ 非アクティブ' do + it 'inactivated_at に日付指定 ⇒ 非アクティブ' do + inactivation_date = '2023-01-15' allow(YAML).to receive(:unsafe_load_file).and_return([ - dojo_base.merge('is_active' => false) + dojo_base.merge('inactivated_at' => inactivation_date) ]) # before expect(Dojo.count).to eq(3) - expect(@dojo_2.is_active).to eq(true) + expect(@dojo_2.active?).to eq(true) # exec expect(@rake[task].invoke).to be_truthy @@ -133,7 +136,8 @@ # after expect(Dojo.count).to eq(3) mod_record = Dojo.find_by(id: @dojo_2.id) - expect(mod_record.is_active).to eq(false) + expect(mod_record.active?).to eq(false) + expect(mod_record.inactivated_at).to eq(Time.zone.parse(inactivation_date)) end end diff --git a/spec/models/dojo_spec.rb b/spec/models/dojo_spec.rb index c0eab7791..b2ff4bbe2 100644 --- a/spec/models/dojo_spec.rb +++ b/spec/models/dojo_spec.rb @@ -21,7 +21,7 @@ it { should respond_to(:tags) } it { should be_valid } - it { expect(Dojo.new.is_active?).to be(true) } + it { expect(Dojo.new.active?).to be(true) } describe "when name is not present" do before { @dojo.name = " " } @@ -86,28 +86,12 @@ end end - describe 'validate inactivated_at for inactive dojos' do - it 'ensures all inactive dojos in YAML have inactivated_at date' do + describe 'validate inactivated_at dates' do + it 'verifies inactivated_at dates are valid when present' do yaml_data = Dojo.load_attributes_from_yaml - inactive_dojos = yaml_data.select { |dojo| dojo['is_active'] == false } - - missing_dates = inactive_dojos.select { |dojo| dojo['inactivated_at'].nil? } - - if missing_dates.any? - missing_info = missing_dates.map { |d| "ID: #{d['id']} (#{d['name']})" }.join(", ") - fail "以下の非アクティブDojoにinactivated_atが設定されていません: #{missing_info}" - end - - expect(inactive_dojos.all? { |dojo| dojo['inactivated_at'].present? }).to be true - end - - it 'verifies inactivated_at dates are valid' do - yaml_data = Dojo.load_attributes_from_yaml - inactive_dojos = yaml_data.select { |dojo| dojo['is_active'] == false } + dojos_with_inactivated_at = yaml_data.select { |dojo| dojo['inactivated_at'].present? } - inactive_dojos.each do |dojo| - next if dojo['inactivated_at'].nil? - + dojos_with_inactivated_at.each do |dojo| # 日付が正しくパースできることを確認 expect { Time.zone.parse(dojo['inactivated_at']) @@ -124,32 +108,6 @@ end end end - - it 'ensures all dojos with inactivated_at have is_active column' do - yaml_data = Dojo.load_attributes_from_yaml - dojos_with_inactivated_at = yaml_data.select { |dojo| dojo['inactivated_at'].present? } - - dojos_with_inactivated_at.each do |dojo| - # inactivated_atがあるDojoは必ずis_activeカラムを持つべき - # (再活性化されたDojoはis_active: trueの可能性があるため、値は問わない) - unless dojo.key?('is_active') - fail "ID: #{dojo['id']} (#{dojo['name']}) はinactivated_atを持っていますが、is_activeカラムがありません" - end - end - - # 統計情報として表示 - if dojos_with_inactivated_at.any? - reactivated_count = dojos_with_inactivated_at.count { |d| d['is_active'] == true } - inactive_count = dojos_with_inactivated_at.count { |d| d['is_active'] == false } - - # テスト出力には表示されないが、デバッグ時に有用 - # puts "inactivated_atを持つDojo数: #{dojos_with_inactivated_at.count}" - # puts " - 現在非アクティブ: #{inactive_count}" - # puts " - 再活性化済み: #{reactivated_count}" - - expect(dojos_with_inactivated_at.count).to eq(inactive_count + reactivated_count) - end - end end # inactivated_at カラムの基本的なテスト @@ -167,22 +125,6 @@ ) end - describe '#sync_active_status' do - it 'sets inactivated_at when is_active becomes false' do - expect(@dojo.inactivated_at).to be_nil - @dojo.update!(is_active: false) - expect(@dojo.inactivated_at).to be_present - end - - it 'clears inactivated_at when is_active becomes true' do - @dojo.update!(is_active: false) - expect(@dojo.inactivated_at).to be_present - - @dojo.update!(is_active: true) - expect(@dojo.inactivated_at).to be_nil - end - end - describe '#active?' do it 'returns true when inactivated_at is nil' do @dojo.inactivated_at = nil diff --git a/spec/models/stat_spec.rb b/spec/models/stat_spec.rb index eb663d832..00207d34f 100644 --- a/spec/models/stat_spec.rb +++ b/spec/models/stat_spec.rb @@ -15,7 +15,6 @@ url: 'https://test1.coderdojo.jp', created_at: Time.zone.local(2020, 3, 1), prefecture_id: 13, - is_active: false, inactivated_at: Time.zone.local(2022, 6, 15) ) @@ -28,7 +27,6 @@ url: 'https://test2.coderdojo.jp', created_at: Time.zone.local(2021, 1, 1), prefecture_id: 13, - is_active: true, inactivated_at: nil ) @@ -41,7 +39,6 @@ url: 'https://test3.coderdojo.jp', created_at: Time.zone.local(2019, 1, 1), prefecture_id: 13, - is_active: false, inactivated_at: Time.zone.local(2020, 3, 1) ) end @@ -95,7 +92,7 @@ url: 'https://test1.coderdojo.jp', created_at: Time.zone.local(2012, 4, 1), prefecture_id: 13, - is_active: true + inactivated_at: nil ) # 2022年に非アクティブ化される道場 @@ -107,7 +104,6 @@ url: 'https://test2.coderdojo.jp', created_at: Time.zone.local(2019, 1, 1), prefecture_id: 14, - is_active: false, inactivated_at: Time.zone.local(2022, 6, 1) ) @@ -120,7 +116,6 @@ url: 'https://test3.coderdojo.jp', created_at: Time.zone.local(2020, 1, 1), prefecture_id: 27, - is_active: false, inactivated_at: Time.zone.local(2023, 3, 1) ) diff --git a/spec/requests/dojos_spec.rb b/spec/requests/dojos_spec.rb index c2cd29355..809abd498 100644 --- a/spec/requests/dojos_spec.rb +++ b/spec/requests/dojos_spec.rb @@ -8,14 +8,13 @@ @dojo_2020_active = create(:dojo, name: "Test Dojo 2020", created_at: "2020-06-01", - is_active: true + inactivated_at: nil ) # 2020年に作成、2021年に非アクティブ化 @dojo_2020_inactive = create(:dojo, name: "Test Dojo 2020 Inactive", created_at: "2020-01-01", - is_active: false, inactivated_at: "2021-03-01" ) @@ -23,14 +22,13 @@ @dojo_2021_active = create(:dojo, name: "Test Dojo 2021", created_at: "2021-01-01", - is_active: true + inactivated_at: nil ) # 2019年に作成、2020年に非アクティブ化(2020年末時点では非アクティブ) @dojo_2019_inactive = create(:dojo, name: "Test Dojo 2019 Inactive", created_at: "2019-01-01", - is_active: false, inactivated_at: "2020-06-01" ) @@ -38,7 +36,7 @@ @dojo_multi_branch = create(:dojo, name: "Multi Branch Dojo", created_at: "2020-01-01", - is_active: true, + inactivated_at: nil, counter: 3 ) end @@ -151,7 +149,6 @@ # 重要: この道場は2021年3月に非アクティブ化されたが、 # 2020年末時点ではアクティブだったので、inactive-item クラスを持たないべき - # 現在のコードはここで失敗するはず(現在の is_active: false を使っているため) expect(dojo_row).not_to include('class="inactive-item"') end