railsのSSRからJS系フレームワークで複数のAPIを叩く際の思ったこと。

Railsのようなerb形式を用いてウェブページを生成するアプローチは、一般的に「サーバーサイドレンダリング (SSR)」と呼ばれています。

前提として、form_forを使ってコントローラーメソッドを呼び出していました。

```erb
  <%= form_for @article, url: articles_path do |f| %>
    <!-- フィールドなど -->
    <%= f.label :title %>
    <%= f.text_field :title %>

    <%= f.label :content %>
    <%= f.text_area :content %>

    <%= f.submit "Create" %>
  <% end %>
```

実装要件として、対象のコントローラーメソッドの前に他のコントローラーメソッドを呼び出したいということでした。
AngularJSを使っていたので、ボタンの押下されたタイミングでAngularJS側で他のコントローラーメソッドを呼び出しをする。

その後に、対象のコントローラーメソッドを呼び出す。みたいな実装をしました。

以下の記事のような実装です。
https://qiita.com/kenogi/items/cd66e59f6606afbb6219

## form_forでは、複数のAPIを叩くのは無理そう
chatGPTに聞いたけど、対象のコントローラーメソッドに変更を加えていた。う〜ん、変更は加えたくない。。。。微妙。

`form_for`を使用して非同期処理を実行することができます。非同期のフォーム送信を実行するには、`:remote => true`オプションを`form_for`に追加します。これはRailsのUJS（Unobtrusive JavaScript）機能と連動して動作します。

### 非同期処理を使用した`form_for`の例

以下は、非同期で`ArticlesController`の`create`アクションを呼び出す例です。

```erb
<%= form_for @article, remote: true do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>

  <%= f.label :content %>
  <%= f.text_area :content %>

  <%= f.submit "Create" %>
<% end %>
```

このフォームが送信されると、`ArticlesController`の`create`アクションが呼び出されますが、通常のHTTPリクエストではなく、AJAXリクエストとして処理されます。

### Aコントローラーメソッドの後にBコントローラーメソッドのAPIを叩く例

Aコントローラーメソッド（例: `ArticlesController`の`create`アクション）が完了した後、BコントローラーメソッドのAPI（例: `NotificationsController`の`send_notification`アクション）を叩きたい場合、以下のような手順をとります。

1. **コントローラの変更**: `ArticlesController`の`create`アクションで、記事の作成が成功した後に`NotificationsController`のメソッドを呼び出します。

```ruby
class ArticlesController < ApplicationController
  def create
    @article = Article.new(article_params)
    if @article.save
      # 通知の送信
      NotificationsController.new.send_notification(@article)
      # ... その他の処理
    else
      # ... エラー処理
    end
  end

  # ... その他のメソッド
end
```

2. **新しいコントローラの追加**: 通知を送るための`NotificationsController`を作成します。

```ruby
class NotificationsController < ApplicationController
  def send_notification(article)
    # 通知の送信ロジック
    # 例: APIを叩く、メールを送信する、など
  end
end
```

このアプローチは、コントローラ間でのメソッドの呼び出しの例です。ただし、このような設計は、複雑性の増加や再利用性の低下を招く可能性があります。そのため、実際のアプリケーション設計においては、サービスオブジェクトやバックグラウンドジョブ、Observerパターンなどの設計パターンを検討する価値があります。

## 複数API叩くなら、JSで書いた方がいい。
すでにrailsのSSRがあった状態だったので、既存のform_forを使いながらAngularでもう一つのAPIを叩きに行く。
また、Angularで叩くなら共通処理をサービスに記述しておくと他のコンポーネントからの呼び出しも可能になるので複数APIを叩くのも簡単になる。

ちなみに、AngularJSではBControllerからAのControllerの関数を呼び出す必要があったのでサービスにしておいた方がいいのかも。

GPTにアドバイスをもらった。

AngularJSのコントローラーを`AController`と`BController`に書き換えた例は以下の通りです。

まず、サービスを作成します。

```javascript
myApp.service('sharedService', function() {
  var sharedData = {};

  // 共有する関数を定義
  sharedData.sharedFunction = function() {
    // ここに共有する関数のロジックを記述
    console.log('共有関数が呼び出されました');
  };

  return sharedData;
});
```

次に、`AController`と`BController`でサービスを注入し、共有関数を使用します。

```javascript
myApp.controller('AController', function($scope, sharedService) {
  $scope.message = 'こんにちは、AngularJS!';

  // 共有関数を呼び出す
  $scope.callSharedFunction = function() {
    sharedService.sharedFunction();
  };
});

myApp.controller('BController', function($scope, sharedService) {
  // 共有関数を呼び出す
  $scope.callSharedFunction = function() {
    sharedService.sharedFunction();
  };
});
```

上記の例では、`sharedService`を作成し、それを`AController`と`BController`に注入しました。それぞれのコントローラー内で`callSharedFunction`を呼び出すことで、共有関数を呼び出すことができます。

`AController`内で`callSharedFunction`を呼び出すと、コンソールに「共有関数が呼び出されました」というメッセージが表示されるでしょう。同様に、`BController`でも共有関数を呼び出すことができます。

## GPTにフィードバックをいただきました

了解しました。指摘された点を踏まえて、フィードバックを提供させていただきます。

## バックエンドのフィードバック:

1. **設計原則**: MVCアーキテクチャでは、モデル、ビュー、コントローラが明確に分離されるべきです。コントローラの主な役割は、リクエストの処理と適切なレスポンスの提供です。API呼び出しや他のロジックはモデルやサービスクラスに委譲すべきです。

2. **サービスの利用**: Railsでは、複雑なビジネスロジックや外部APIの呼び出しを行う場合、サービスオブジェクトやコンシャンを利用することが推奨されています。これにより、コントローラの複雑性を減少させ、テストのしやすさを向上させることができます。

3. **非同期処理の取り扱い**: Railsの`:remote => true`オプションを使用して非同期処理を実行する場合、JavaScript側で適切なレスポンス処理が必要です。成功や失敗時の処理をきちんと設定することが重要です。

## フロントエンドのフィードバック:

1. **AngularJSの役割**: AngularJSを使用する場合、状態管理やDOMの更新などのロジックをJS側で行うのが一般的です。Railsの`form_for`を利用しつつAngularJSでのAPI呼び出しを行う場合、どちらの技術の責任範囲で何を行うかを明確にする必要があります。

2. **サービスの利用**: AngularJSではサービスを利用することで、ロジックの再利用や状態の共有が容易になります。特に複数のコントローラ間で同じロジックを使用する場合や、状態を共有する必要がある場合、サービスの利用は非常に効果的です。

3. **非同期処理のエラーハンドリング**: AngularJSを使用してAPI呼び出しを行う場合、非同期処理のエラーハンドリングを適切に行うことが重要です。`.then()`や`.catch()`を適切に利用して、成功時と失敗時の処理を明確に定義することが推奨されます。

4. **明確な責任の分離**: RailsとAngularJSの組み合わせを使用する場合、各技術の責任範囲を明確にすることが重要です。例えば、データの取得や更新のロジックはAngularJS側で行い、データの永続化や認証などのバックエンドのロジックはRails側で行う、といったように明確に役割を分けることが推奨されます。

最後に、既存のシステムに新しい技術を組み込む際は、その技術が解決する問題や提供する価値を明確に理解して、適切なアーキテクチャや設計を選択することが重要です。