debug-mcp 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +83 -0
- data/LICENSE +21 -0
- data/README.ja.md +383 -0
- data/README.md +384 -0
- data/examples/01_simple_bug.rb +43 -0
- data/examples/02_data_pipeline.rb +93 -0
- data/examples/03_recursion.rb +96 -0
- data/examples/RAILS_SCENARIOS.md +350 -0
- data/examples/SCENARIOS.md +142 -0
- data/examples/rails_test_app/setup.sh +428 -0
- data/examples/rails_test_app/testapp/.dockerignore +10 -0
- data/examples/rails_test_app/testapp/.ruby-version +1 -0
- data/examples/rails_test_app/testapp/Dockerfile +23 -0
- data/examples/rails_test_app/testapp/Gemfile +17 -0
- data/examples/rails_test_app/testapp/README.md +65 -0
- data/examples/rails_test_app/testapp/Rakefile +6 -0
- data/examples/rails_test_app/testapp/app/assets/images/.keep +0 -0
- data/examples/rails_test_app/testapp/app/assets/stylesheets/application.css +1 -0
- data/examples/rails_test_app/testapp/app/controllers/application_controller.rb +4 -0
- data/examples/rails_test_app/testapp/app/controllers/concerns/.keep +0 -0
- data/examples/rails_test_app/testapp/app/controllers/dashboard_controller.rb +38 -0
- data/examples/rails_test_app/testapp/app/controllers/health_controller.rb +11 -0
- data/examples/rails_test_app/testapp/app/controllers/orders_controller.rb +100 -0
- data/examples/rails_test_app/testapp/app/controllers/posts_controller.rb +82 -0
- data/examples/rails_test_app/testapp/app/controllers/sessions_controller.rb +25 -0
- data/examples/rails_test_app/testapp/app/controllers/users_controller.rb +44 -0
- data/examples/rails_test_app/testapp/app/helpers/application_helper.rb +2 -0
- data/examples/rails_test_app/testapp/app/models/application_record.rb +3 -0
- data/examples/rails_test_app/testapp/app/models/comment.rb +8 -0
- data/examples/rails_test_app/testapp/app/models/concerns/.keep +0 -0
- data/examples/rails_test_app/testapp/app/models/order.rb +56 -0
- data/examples/rails_test_app/testapp/app/models/order_item.rb +16 -0
- data/examples/rails_test_app/testapp/app/models/post.rb +29 -0
- data/examples/rails_test_app/testapp/app/models/user.rb +34 -0
- data/examples/rails_test_app/testapp/app/services/order_report_service.rb +40 -0
- data/examples/rails_test_app/testapp/app/views/layouts/application.html.erb +28 -0
- data/examples/rails_test_app/testapp/app/views/pwa/manifest.json.erb +22 -0
- data/examples/rails_test_app/testapp/app/views/pwa/service-worker.js +26 -0
- data/examples/rails_test_app/testapp/bin/ci +6 -0
- data/examples/rails_test_app/testapp/bin/dev +2 -0
- data/examples/rails_test_app/testapp/bin/rails +4 -0
- data/examples/rails_test_app/testapp/bin/rake +4 -0
- data/examples/rails_test_app/testapp/bin/setup +35 -0
- data/examples/rails_test_app/testapp/config/application.rb +42 -0
- data/examples/rails_test_app/testapp/config/boot.rb +3 -0
- data/examples/rails_test_app/testapp/config/ci.rb +14 -0
- data/examples/rails_test_app/testapp/config/database.yml +32 -0
- data/examples/rails_test_app/testapp/config/environment.rb +5 -0
- data/examples/rails_test_app/testapp/config/environments/development.rb +54 -0
- data/examples/rails_test_app/testapp/config/environments/production.rb +67 -0
- data/examples/rails_test_app/testapp/config/environments/test.rb +42 -0
- data/examples/rails_test_app/testapp/config/initializers/content_security_policy.rb +29 -0
- data/examples/rails_test_app/testapp/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/rails_test_app/testapp/config/initializers/inflections.rb +16 -0
- data/examples/rails_test_app/testapp/config/locales/en.yml +31 -0
- data/examples/rails_test_app/testapp/config/puma.rb +39 -0
- data/examples/rails_test_app/testapp/config/routes.rb +34 -0
- data/examples/rails_test_app/testapp/config.ru +6 -0
- data/examples/rails_test_app/testapp/db/migrate/20260216002916_create_users.rb +12 -0
- data/examples/rails_test_app/testapp/db/migrate/20260216002919_create_posts.rb +13 -0
- data/examples/rails_test_app/testapp/db/migrate/20260216002922_create_comments.rb +11 -0
- data/examples/rails_test_app/testapp/db/migrate/20260222000001_create_orders.rb +14 -0
- data/examples/rails_test_app/testapp/db/migrate/20260222000002_create_order_items.rb +13 -0
- data/examples/rails_test_app/testapp/db/schema.rb +71 -0
- data/examples/rails_test_app/testapp/db/seeds.rb +85 -0
- data/examples/rails_test_app/testapp/docker-compose.yml +21 -0
- data/examples/rails_test_app/testapp/docker-entrypoint.sh +10 -0
- data/examples/rails_test_app/testapp/lib/tasks/.keep +0 -0
- data/examples/rails_test_app/testapp/log/.keep +0 -0
- data/examples/rails_test_app/testapp/public/400.html +135 -0
- data/examples/rails_test_app/testapp/public/404.html +135 -0
- data/examples/rails_test_app/testapp/public/406-unsupported-browser.html +135 -0
- data/examples/rails_test_app/testapp/public/422.html +135 -0
- data/examples/rails_test_app/testapp/public/500.html +135 -0
- data/examples/rails_test_app/testapp/public/icon.png +0 -0
- data/examples/rails_test_app/testapp/public/icon.svg +3 -0
- data/examples/rails_test_app/testapp/public/robots.txt +1 -0
- data/examples/rails_test_app/testapp/script/.keep +0 -0
- data/examples/rails_test_app/testapp/storage/.keep +0 -0
- data/examples/rails_test_app/testapp/tmp/.keep +0 -0
- data/examples/rails_test_app/testapp/tmp/pids/.keep +0 -0
- data/examples/rails_test_app/testapp/tmp/storage/.keep +0 -0
- data/examples/rails_test_app/testapp/vendor/.keep +0 -0
- data/exe/debug-mcp +39 -0
- data/exe/debug-rails +127 -0
- data/lib/debug_mcp/client_cleanup.rb +102 -0
- data/lib/debug_mcp/code_safety_analyzer.rb +124 -0
- data/lib/debug_mcp/debug_client.rb +1143 -0
- data/lib/debug_mcp/exit_message_builder.rb +112 -0
- data/lib/debug_mcp/pending_http_helper.rb +25 -0
- data/lib/debug_mcp/rails_helper.rb +155 -0
- data/lib/debug_mcp/server.rb +364 -0
- data/lib/debug_mcp/session_manager.rb +436 -0
- data/lib/debug_mcp/stop_event_annotator.rb +152 -0
- data/lib/debug_mcp/tcp_session_discovery.rb +226 -0
- data/lib/debug_mcp/tools/connect.rb +669 -0
- data/lib/debug_mcp/tools/continue_execution.rb +161 -0
- data/lib/debug_mcp/tools/disconnect.rb +169 -0
- data/lib/debug_mcp/tools/evaluate_code.rb +354 -0
- data/lib/debug_mcp/tools/finish.rb +84 -0
- data/lib/debug_mcp/tools/get_context.rb +217 -0
- data/lib/debug_mcp/tools/get_source.rb +193 -0
- data/lib/debug_mcp/tools/inspect_object.rb +107 -0
- data/lib/debug_mcp/tools/list_debug_sessions.rb +60 -0
- data/lib/debug_mcp/tools/list_files.rb +189 -0
- data/lib/debug_mcp/tools/list_paused_sessions.rb +108 -0
- data/lib/debug_mcp/tools/next.rb +70 -0
- data/lib/debug_mcp/tools/rails_info.rb +200 -0
- data/lib/debug_mcp/tools/rails_model.rb +362 -0
- data/lib/debug_mcp/tools/rails_routes.rb +186 -0
- data/lib/debug_mcp/tools/read_file.rb +214 -0
- data/lib/debug_mcp/tools/remove_breakpoint.rb +173 -0
- data/lib/debug_mcp/tools/run_debug_command.rb +55 -0
- data/lib/debug_mcp/tools/run_script.rb +293 -0
- data/lib/debug_mcp/tools/set_breakpoint.rb +206 -0
- data/lib/debug_mcp/tools/step.rb +67 -0
- data/lib/debug_mcp/tools/trigger_request.rb +515 -0
- data/lib/debug_mcp/version.rb +5 -0
- data/lib/debug_mcp.rb +40 -0
- metadata +251 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# debug-mcp Rails テスト用アプリのセットアップスクリプト
|
|
3
|
+
#
|
|
4
|
+
# 使い方:
|
|
5
|
+
# cd examples/rails_test_app
|
|
6
|
+
# bash setup.sh
|
|
7
|
+
#
|
|
8
|
+
# これにより、debug-mcpのRailsツールをテストするための
|
|
9
|
+
# 最小限のRailsアプリケーションが生成されます。
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
APP_DIR="$(cd "$(dirname "$0")" && pwd)/testapp"
|
|
14
|
+
|
|
15
|
+
echo "=== debug-mcp Rails テストアプリ セットアップ ==="
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# 既存のアプリがあれば確認
|
|
19
|
+
if [ -d "$APP_DIR" ]; then
|
|
20
|
+
echo "既存のテストアプリが見つかりました: $APP_DIR"
|
|
21
|
+
read -p "削除して再作成しますか? (y/N): " confirm
|
|
22
|
+
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
|
|
23
|
+
echo "中止しました。"
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
rm -rf "$APP_DIR"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo "1/6: Rails アプリを生成中..."
|
|
30
|
+
rails new "$APP_DIR" \
|
|
31
|
+
--database=sqlite3 \
|
|
32
|
+
--skip-git \
|
|
33
|
+
--skip-docker \
|
|
34
|
+
--skip-action-mailer \
|
|
35
|
+
--skip-action-mailbox \
|
|
36
|
+
--skip-action-text \
|
|
37
|
+
--skip-active-storage \
|
|
38
|
+
--skip-action-cable \
|
|
39
|
+
--skip-hotwire \
|
|
40
|
+
--skip-jbuilder \
|
|
41
|
+
--skip-test \
|
|
42
|
+
--skip-system-test \
|
|
43
|
+
--skip-bootsnap \
|
|
44
|
+
--skip-asset-pipeline \
|
|
45
|
+
--skip-javascript \
|
|
46
|
+
--minimal \
|
|
47
|
+
--quiet
|
|
48
|
+
|
|
49
|
+
cd "$APP_DIR"
|
|
50
|
+
|
|
51
|
+
# debug gem を追加
|
|
52
|
+
echo "" >> Gemfile
|
|
53
|
+
echo '# debug-mcp テスト用' >> Gemfile
|
|
54
|
+
echo 'gem "debug"' >> Gemfile
|
|
55
|
+
bundle install --quiet
|
|
56
|
+
|
|
57
|
+
echo "2/6: モデルを生成中..."
|
|
58
|
+
|
|
59
|
+
# User モデル: バリデーション、enum、アソシエーション
|
|
60
|
+
bin/rails generate model User \
|
|
61
|
+
name:string \
|
|
62
|
+
email:string \
|
|
63
|
+
role:integer \
|
|
64
|
+
active:boolean \
|
|
65
|
+
--quiet --no-test-framework
|
|
66
|
+
|
|
67
|
+
# Post モデル: belongs_to、スコープ
|
|
68
|
+
bin/rails generate model Post \
|
|
69
|
+
title:string \
|
|
70
|
+
body:text \
|
|
71
|
+
status:integer \
|
|
72
|
+
user:references \
|
|
73
|
+
published_at:datetime \
|
|
74
|
+
--quiet --no-test-framework
|
|
75
|
+
|
|
76
|
+
# Comment モデル: ポリモーフィック的な関連
|
|
77
|
+
bin/rails generate model Comment \
|
|
78
|
+
body:text \
|
|
79
|
+
user:references \
|
|
80
|
+
post:references \
|
|
81
|
+
--quiet --no-test-framework
|
|
82
|
+
|
|
83
|
+
echo "3/6: モデルコードを設定中..."
|
|
84
|
+
|
|
85
|
+
# User モデル
|
|
86
|
+
cat > app/models/user.rb << 'RUBY'
|
|
87
|
+
class User < ApplicationRecord
|
|
88
|
+
has_many :posts, dependent: :destroy
|
|
89
|
+
has_many :comments, dependent: :destroy
|
|
90
|
+
|
|
91
|
+
validates :name, presence: true, length: { maximum: 50 }
|
|
92
|
+
validates :email, presence: true, uniqueness: true,
|
|
93
|
+
format: { with: /\A[^@\s]+@[^@\s]+\z/ }
|
|
94
|
+
|
|
95
|
+
enum :role, { guest: 0, member: 1, editor: 2, admin: 3 }
|
|
96
|
+
|
|
97
|
+
scope :active, -> { where(active: true) }
|
|
98
|
+
scope :admins, -> { where(role: :admin) }
|
|
99
|
+
scope :recent, -> { order(created_at: :desc) }
|
|
100
|
+
|
|
101
|
+
def display_name
|
|
102
|
+
"#{name} (#{role})"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
RUBY
|
|
106
|
+
|
|
107
|
+
# Post モデル
|
|
108
|
+
cat > app/models/post.rb << 'RUBY'
|
|
109
|
+
class Post < ApplicationRecord
|
|
110
|
+
belongs_to :user
|
|
111
|
+
has_many :comments, dependent: :destroy
|
|
112
|
+
|
|
113
|
+
validates :title, presence: true, length: { maximum: 100 }
|
|
114
|
+
validates :body, presence: true
|
|
115
|
+
|
|
116
|
+
enum :status, { draft: 0, published: 1, archived: 2 }
|
|
117
|
+
|
|
118
|
+
scope :published, -> { where(status: :published) }
|
|
119
|
+
scope :drafts, -> { where(status: :draft) }
|
|
120
|
+
scope :recent, -> { order(published_at: :desc) }
|
|
121
|
+
scope :by_user, ->(user_id) { where(user_id: user_id) }
|
|
122
|
+
|
|
123
|
+
def summary
|
|
124
|
+
body.to_s.truncate(100)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
RUBY
|
|
128
|
+
|
|
129
|
+
# Comment モデル
|
|
130
|
+
cat > app/models/comment.rb << 'RUBY'
|
|
131
|
+
class Comment < ApplicationRecord
|
|
132
|
+
belongs_to :user
|
|
133
|
+
belongs_to :post
|
|
134
|
+
|
|
135
|
+
validates :body, presence: true, length: { minimum: 3 }
|
|
136
|
+
|
|
137
|
+
scope :recent, -> { order(created_at: :desc) }
|
|
138
|
+
end
|
|
139
|
+
RUBY
|
|
140
|
+
|
|
141
|
+
echo "4/6: コントローラとルーティングを設定中..."
|
|
142
|
+
|
|
143
|
+
# UsersController
|
|
144
|
+
mkdir -p app/controllers
|
|
145
|
+
cat > app/controllers/users_controller.rb << 'RUBY'
|
|
146
|
+
class UsersController < ApplicationController
|
|
147
|
+
before_action :set_user, only: [:show, :update, :destroy]
|
|
148
|
+
|
|
149
|
+
def index
|
|
150
|
+
@users = User.all
|
|
151
|
+
render json: @users
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def show
|
|
155
|
+
render json: @user.as_json(include: { posts: { only: [:id, :title, :status] } })
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def create
|
|
159
|
+
@user = User.new(user_params)
|
|
160
|
+
if @user.save
|
|
161
|
+
render json: @user, status: :created
|
|
162
|
+
else
|
|
163
|
+
render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def update
|
|
168
|
+
if @user.update(user_params)
|
|
169
|
+
render json: @user
|
|
170
|
+
else
|
|
171
|
+
render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def destroy
|
|
176
|
+
@user.destroy
|
|
177
|
+
head :no_content
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
def set_user
|
|
183
|
+
@user = User.find(params[:id])
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def user_params
|
|
187
|
+
params.permit(:name, :email, :role, :active)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
RUBY
|
|
191
|
+
|
|
192
|
+
# PostsController
|
|
193
|
+
cat > app/controllers/posts_controller.rb << 'RUBY'
|
|
194
|
+
class PostsController < ApplicationController
|
|
195
|
+
before_action :set_post, only: [:show, :update]
|
|
196
|
+
|
|
197
|
+
def index
|
|
198
|
+
@posts = Post.published.includes(:user).recent
|
|
199
|
+
render json: @posts.as_json(include: { user: { only: [:id, :name] } })
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def show
|
|
203
|
+
render json: @post.as_json(
|
|
204
|
+
include: {
|
|
205
|
+
user: { only: [:id, :name] },
|
|
206
|
+
comments: { include: { user: { only: [:id, :name] } } }
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def create
|
|
212
|
+
@post = Post.new(post_params)
|
|
213
|
+
if @post.save
|
|
214
|
+
render json: @post, status: :created
|
|
215
|
+
else
|
|
216
|
+
render json: { errors: @post.errors.full_messages }, status: :unprocessable_entity
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def update
|
|
221
|
+
if @post.update(post_params)
|
|
222
|
+
render json: @post
|
|
223
|
+
else
|
|
224
|
+
render json: { errors: @post.errors.full_messages }, status: :unprocessable_entity
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# 検索エンドポイント(デバッグ向け:N+1問題あり)
|
|
229
|
+
def search
|
|
230
|
+
query = params[:q].to_s
|
|
231
|
+
@posts = Post.where("title LIKE ?", "%#{query}%")
|
|
232
|
+
|
|
233
|
+
# 意図的なN+1(デバッグで発見させる)
|
|
234
|
+
results = @posts.map do |post|
|
|
235
|
+
{
|
|
236
|
+
id: post.id,
|
|
237
|
+
title: post.title,
|
|
238
|
+
author: post.user.name,
|
|
239
|
+
comments_count: post.comments.count
|
|
240
|
+
}
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
render json: results
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
private
|
|
247
|
+
|
|
248
|
+
def set_post
|
|
249
|
+
@post = Post.find(params[:id])
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def post_params
|
|
253
|
+
params.permit(:title, :body, :status, :user_id, :published_at)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
RUBY
|
|
257
|
+
|
|
258
|
+
# SessionsController(Cookie テスト用)
|
|
259
|
+
cat > app/controllers/sessions_controller.rb << 'RUBY'
|
|
260
|
+
class SessionsController < ApplicationController
|
|
261
|
+
def create
|
|
262
|
+
user = User.find_by(email: params[:email])
|
|
263
|
+
if user
|
|
264
|
+
session[:user_id] = user.id
|
|
265
|
+
render json: { message: "Logged in", user: user.as_json(only: [:id, :name, :email, :role]) }
|
|
266
|
+
else
|
|
267
|
+
render json: { error: "Invalid email" }, status: :unauthorized
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def show
|
|
272
|
+
if session[:user_id]
|
|
273
|
+
user = User.find(session[:user_id])
|
|
274
|
+
render json: { logged_in: true, user: user.as_json(only: [:id, :name, :email, :role]) }
|
|
275
|
+
else
|
|
276
|
+
render json: { logged_in: false }
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def destroy
|
|
281
|
+
session.delete(:user_id)
|
|
282
|
+
render json: { message: "Logged out" }
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
RUBY
|
|
286
|
+
|
|
287
|
+
# HealthController(シンプルなテスト用)
|
|
288
|
+
cat > app/controllers/health_controller.rb << 'RUBY'
|
|
289
|
+
class HealthController < ApplicationController
|
|
290
|
+
def show
|
|
291
|
+
render json: {
|
|
292
|
+
status: "ok",
|
|
293
|
+
rails_version: Rails::VERSION::STRING,
|
|
294
|
+
ruby_version: RUBY_VERSION,
|
|
295
|
+
environment: Rails.env,
|
|
296
|
+
time: Time.current.iso8601
|
|
297
|
+
}
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
RUBY
|
|
301
|
+
|
|
302
|
+
# DashboardController(HTMLレスポンス テスト用)
|
|
303
|
+
cat > app/controllers/dashboard_controller.rb << 'RUBY'
|
|
304
|
+
class DashboardController < ApplicationController
|
|
305
|
+
def index
|
|
306
|
+
@stats = {
|
|
307
|
+
users: User.count,
|
|
308
|
+
posts: Post.count,
|
|
309
|
+
comments: Comment.count,
|
|
310
|
+
published_posts: Post.published.count
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
render html: <<~HTML.html_safe
|
|
314
|
+
<!DOCTYPE html>
|
|
315
|
+
<html>
|
|
316
|
+
<head><title>Dashboard</title></head>
|
|
317
|
+
<body>
|
|
318
|
+
<h1>Dashboard</h1>
|
|
319
|
+
<ul>
|
|
320
|
+
<li>Users: #{@stats[:users]}</li>
|
|
321
|
+
<li>Posts: #{@stats[:posts]}</li>
|
|
322
|
+
<li>Comments: #{@stats[:comments]}</li>
|
|
323
|
+
<li>Published: #{@stats[:published_posts]}</li>
|
|
324
|
+
</ul>
|
|
325
|
+
</body>
|
|
326
|
+
</html>
|
|
327
|
+
HTML
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
RUBY
|
|
331
|
+
|
|
332
|
+
# ルーティング
|
|
333
|
+
cat > config/routes.rb << 'RUBY'
|
|
334
|
+
Rails.application.routes.draw do
|
|
335
|
+
resources :users, only: [:index, :show, :create, :update, :destroy]
|
|
336
|
+
|
|
337
|
+
resources :posts, only: [:index, :show, :create, :update] do
|
|
338
|
+
collection do
|
|
339
|
+
get :search
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# セッション管理
|
|
344
|
+
post "/login", to: "sessions#create"
|
|
345
|
+
get "/me", to: "sessions#show"
|
|
346
|
+
delete "/logout", to: "sessions#destroy"
|
|
347
|
+
|
|
348
|
+
# ヘルスチェック
|
|
349
|
+
get "/health", to: "health#show"
|
|
350
|
+
|
|
351
|
+
# ダッシュボード(HTML)
|
|
352
|
+
get "/dashboard", to: "dashboard#index"
|
|
353
|
+
|
|
354
|
+
# ルートパス
|
|
355
|
+
root "health#show"
|
|
356
|
+
end
|
|
357
|
+
RUBY
|
|
358
|
+
|
|
359
|
+
echo "5/6: データベースをセットアップ中..."
|
|
360
|
+
|
|
361
|
+
bin/rails db:create db:migrate --quiet
|
|
362
|
+
|
|
363
|
+
# シードデータ
|
|
364
|
+
cat > db/seeds.rb << 'RUBY'
|
|
365
|
+
puts "シードデータを作成中..."
|
|
366
|
+
|
|
367
|
+
# ユーザー
|
|
368
|
+
alice = User.create!(name: "Alice", email: "alice@example.com", role: :admin, active: true)
|
|
369
|
+
bob = User.create!(name: "Bob", email: "bob@example.com", role: :editor, active: true)
|
|
370
|
+
carol = User.create!(name: "Carol", email: "carol@example.com", role: :member, active: true)
|
|
371
|
+
dave = User.create!(name: "Dave", email: "dave@example.com", role: :guest, active: false)
|
|
372
|
+
|
|
373
|
+
# 投稿
|
|
374
|
+
post1 = Post.create!(
|
|
375
|
+
title: "Rails デバッグ入門",
|
|
376
|
+
body: "debug gemを使ったRailsアプリケーションのデバッグ方法について解説します。breakpointの設定、変数の確認、ステップ実行など基本的なデバッグ技法を紹介します。",
|
|
377
|
+
status: :published,
|
|
378
|
+
user: alice,
|
|
379
|
+
published_at: 2.days.ago
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
post2 = Post.create!(
|
|
383
|
+
title: "ActiveRecordのN+1問題を解決する",
|
|
384
|
+
body: "includesやpreloadを使ってN+1クエリを解消する方法を紹介します。BulletやProsopiteなどの検出ツールも併せて解説します。",
|
|
385
|
+
status: :published,
|
|
386
|
+
user: bob,
|
|
387
|
+
published_at: 1.day.ago
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
post3 = Post.create!(
|
|
391
|
+
title: "下書き: テスト駆動開発のすすめ",
|
|
392
|
+
body: "RSpecを使ったTDDの実践方法について。まだ書きかけです。",
|
|
393
|
+
status: :draft,
|
|
394
|
+
user: alice
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
post4 = Post.create!(
|
|
398
|
+
title: "アーカイブ済み: 古い記事",
|
|
399
|
+
body: "この記事はアーカイブされました。",
|
|
400
|
+
status: :archived,
|
|
401
|
+
user: carol
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# コメント
|
|
405
|
+
Comment.create!(body: "とても分かりやすい記事です!", user: bob, post: post1)
|
|
406
|
+
Comment.create!(body: "binding.breakの使い方も知りたいです。", user: carol, post: post1)
|
|
407
|
+
Comment.create!(body: "N+1問題に困っていたので助かりました。", user: alice, post: post2)
|
|
408
|
+
Comment.create!(body: "Bulletの設定方法をもう少し詳しく書いてほしいです。", user: dave, post: post2)
|
|
409
|
+
|
|
410
|
+
puts "完了: ユーザー#{User.count}人、投稿#{Post.count}件、コメント#{Comment.count}件"
|
|
411
|
+
RUBY
|
|
412
|
+
|
|
413
|
+
bin/rails db:seed
|
|
414
|
+
|
|
415
|
+
echo "6/6: 動作確認..."
|
|
416
|
+
|
|
417
|
+
echo ""
|
|
418
|
+
echo "=== セットアップ完了 ==="
|
|
419
|
+
echo ""
|
|
420
|
+
echo "テストアプリの起動方法:"
|
|
421
|
+
echo " cd $APP_DIR"
|
|
422
|
+
echo " RUBY_DEBUG_OPEN=true bin/rails server -p 3999"
|
|
423
|
+
echo ""
|
|
424
|
+
echo "debug-mcpからの接続:"
|
|
425
|
+
echo " 1. connect で Rails プロセスに接続"
|
|
426
|
+
echo " 2. rails_info でアプリ概要を確認"
|
|
427
|
+
echo " 3. 詳しいシナリオは examples/RAILS_SCENARIOS.md を参照"
|
|
428
|
+
echo ""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.4
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
FROM ruby:3.3.4-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update -qq && \
|
|
4
|
+
apt-get install --no-install-recommends -y \
|
|
5
|
+
build-essential \
|
|
6
|
+
libsqlite3-dev \
|
|
7
|
+
curl && \
|
|
8
|
+
rm -rf /var/lib/apt/lists/*
|
|
9
|
+
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
|
|
12
|
+
COPY Gemfile Gemfile.lock ./
|
|
13
|
+
RUN bundle install
|
|
14
|
+
|
|
15
|
+
COPY . .
|
|
16
|
+
|
|
17
|
+
COPY docker-entrypoint.sh /usr/bin/
|
|
18
|
+
RUN chmod +x /usr/bin/docker-entrypoint.sh
|
|
19
|
+
|
|
20
|
+
EXPOSE 3000 12345
|
|
21
|
+
|
|
22
|
+
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
23
|
+
CMD ["bin/rails", "server", "-b", "0.0.0.0"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
source "https://rubygems.org"
|
|
2
|
+
|
|
3
|
+
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
|
|
4
|
+
gem "rails", "~> 8.1.1"
|
|
5
|
+
# Use sqlite3 as the database for Active Record
|
|
6
|
+
gem "sqlite3", ">= 2.1"
|
|
7
|
+
# Use the Puma web server [https://github.com/puma/puma]
|
|
8
|
+
gem "puma", ">= 5.0"
|
|
9
|
+
|
|
10
|
+
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
|
11
|
+
gem "tzinfo-data", platforms: %i[ windows jruby ]
|
|
12
|
+
|
|
13
|
+
group :development, :test do
|
|
14
|
+
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
|
|
15
|
+
gem "debug", platforms: %i[ mri windows ]
|
|
16
|
+
end
|
|
17
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Rails Test App for debug-mcp
|
|
2
|
+
|
|
3
|
+
debug-mcpの動作検証用Railsアプリケーション。ローカルでもDockerでも実行可能。
|
|
4
|
+
|
|
5
|
+
## ローカル実行
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bundle install
|
|
9
|
+
bin/rails db:prepare
|
|
10
|
+
RUBY_DEBUG_OPEN=true bin/rails server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
debug-mcpから接続:
|
|
14
|
+
```
|
|
15
|
+
connect # Unix socketで自動検出
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Docker実行
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
docker compose up --build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
起動確認:
|
|
25
|
+
```bash
|
|
26
|
+
curl http://localhost:3000/health
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
debug-mcpから接続:
|
|
30
|
+
```
|
|
31
|
+
connect(host: "localhost", port: 12345)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Dockerデバッグの流れ
|
|
35
|
+
|
|
36
|
+
接続するとtrap context(Pumaのシグナルハンドラ内)で停止します。
|
|
37
|
+
DB操作やモデルのautoloadingは使えないため、ブレークポイント経由で通常コンテキストに移行します:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
1. set_breakpoint(file: "app/controllers/users_controller.rb", line: 5)
|
|
41
|
+
2. trigger_request(method: "GET", url: "http://localhost:3000/users")
|
|
42
|
+
3. # ブレークポイントにヒット → evaluate_code, get_context 等が使える
|
|
43
|
+
4. continue_execution # リクエスト完了
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
停止:
|
|
47
|
+
```bash
|
|
48
|
+
docker compose down
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## エンドポイント
|
|
52
|
+
|
|
53
|
+
| メソッド | パス | 説明 |
|
|
54
|
+
|---------|------|------|
|
|
55
|
+
| GET | /health | ヘルスチェック |
|
|
56
|
+
| GET | /users | ユーザー一覧 |
|
|
57
|
+
| GET | /users/:id | ユーザー詳細 |
|
|
58
|
+
| GET | /posts | 投稿一覧 |
|
|
59
|
+
| GET | /orders | 注文一覧 |
|
|
60
|
+
| GET | /dashboard | ダッシュボード(HTML) |
|
|
61
|
+
|
|
62
|
+
## シードデータ
|
|
63
|
+
|
|
64
|
+
- ユーザー4人 (Alice/admin, Bob/editor, Carol/member, Dave/guest)
|
|
65
|
+
- 投稿4件、コメント4件、注文6件
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* Application styles */
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class DashboardController < ApplicationController
|
|
2
|
+
def index
|
|
3
|
+
@stats = {
|
|
4
|
+
users: User.count,
|
|
5
|
+
posts: Post.count,
|
|
6
|
+
comments: Comment.count,
|
|
7
|
+
published_posts: Post.published.count
|
|
8
|
+
}
|
|
9
|
+
@trending = Post.trending(3)
|
|
10
|
+
@revenue = Order.revenue_stats
|
|
11
|
+
|
|
12
|
+
render html: <<~HTML.html_safe
|
|
13
|
+
<!DOCTYPE html>
|
|
14
|
+
<html>
|
|
15
|
+
<head><title>Dashboard</title></head>
|
|
16
|
+
<body>
|
|
17
|
+
<h1>Dashboard</h1>
|
|
18
|
+
<ul>
|
|
19
|
+
<li>Users: #{@stats[:users]}</li>
|
|
20
|
+
<li>Posts: #{@stats[:posts]}</li>
|
|
21
|
+
<li>Comments: #{@stats[:comments]}</li>
|
|
22
|
+
<li>Published: #{@stats[:published_posts]}</li>
|
|
23
|
+
</ul>
|
|
24
|
+
<h2>Trending Posts</h2>
|
|
25
|
+
<ol>
|
|
26
|
+
#{@trending.map { |p| "<li>#{p.title} (#{p.comments.size} comments)</li>" }.join}
|
|
27
|
+
</ol>
|
|
28
|
+
<h2>Revenue</h2>
|
|
29
|
+
<ul>
|
|
30
|
+
<li>Total Revenue: #{@revenue[:total_revenue]} cents</li>
|
|
31
|
+
<li>Average Order: #{@revenue[:average_order]} cents</li>
|
|
32
|
+
<li>Order Count: #{@revenue[:order_count]}</li>
|
|
33
|
+
</ul>
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
36
|
+
HTML
|
|
37
|
+
end
|
|
38
|
+
end
|