Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

メンターダッシュボードに表示しているn日経過の提出物一覧を非vue化したい。 #7947

Open
machida opened this issue Jul 9, 2024 · 6 comments
Assignees

Comments

@machida
Copy link
Member

machida commented Jul 9, 2024

メンターでログインしたときにダッシュボードに表示されるこれが今はVueで実装されているので、Railsのviewに移行する。

貼り付けた画像_2024_07_09_20_02
@Shrimprin
Copy link
Contributor

Shrimprin commented Sep 29, 2024

@komagata @machida
お疲れ様です。
本イシューでは既存のVueをRailsのViewComponentへ置き換えをしています。
ViewCompoentのテストの実装で上手くいかない点があり、アドバイスをいただけますでしょうか 🙇
(※2024/9/30 18:50 エラー内容、エラーが発生するパターンを少し修正しました)

解決したいこと

ViewComponentのテストでActiveDecoratorメソッドがundefined methodエラーとなる。
(以下、ViewComponentのテスト = コンポーネントテストActiveDecoratorメソッド = デコレーターメソッドと記載します)

エラー内容

例えば、ViewComponentのhtmlファイルでuser.icon_titleを呼び出す部分で以下のようなエラーが発生する。
(エラーの発生するテストコードはまだPRには含めていません)
エラーが発生するのはコンポーネントテストから呼び出した時のみで、テスト以外(ブラウザから呼び出す)はエラーは発生しない。

❯ rails test test/components/product/product_component_test.rb
Running via Spring preloader in process 11715
Run options: --seed 21297

# Running:

....E

Error:
Products::ProductComponentTest#test_render_comments_count_when_there_are_comments:
NoMethodError: undefined method `icon_title' for #<User id: ...
...
{中略}
...
    app/components/products/product_component.html.slim:71:in `block in call'
    app/components/products/product_component.html.slim:69:in `call'
    test/components/product/product_component_test.rb:67:in `test_render_comments_count_when_there_are_comments'


rails test test/components/product/product_component_test.rb:64
全文
❯ rails test test/components/product/product_component_test.rb
Running via Spring preloader in process 11715
Run options: --seed 21297

# Running:

....E

Error:
Products::ProductComponentTest#test_render_comments_count_when_there_are_comments:
NoMethodError: undefined method `icon_title' for #<User id: 459775584, login_name: "komagata", email: "[email protected]", crypted_password: "$2a$10$n/xv4/1luueN6plzm2OyDezWlZFyGHjQEf4hwAW1r3k...", salt: "zW3kQ9ubsxQQtzzzs4ap", created_at: "2014-01-01 09:00:01.000000000 +0900", updated_at: "2024-09-26 18:37:04.934627000 +0900", remember_me_token: nil, remember_me_token_expires_at: nil, twitter_account: "komagata", facebook_url: "https://www.facebook.com/fjordllc/komagata1111", blog_url: "http://komagata.org", company_id: 636488896, description: "平日10〜19時勤務です。", accessed_at: nil, github_account: "komagata", adviser: false, nda: true, reset_password_token: nil, reset_password_token_expires_at: nil, reset_password_email_sent_at: nil, mentor: true, graduated_on: nil, course_id: 829913840, retired_on: nil, admin: true, job: "office_worker", organization: "株式会社ロッカ", os: "mac", experience: nil, retire_reason: nil, trainee: false, free: false, customer_id: nil, job_seeking: false, subscription_id: nil, mail_notification: true, job_seeker: false, github_id: nil, github_collaborator: true, name: "Komagata Masaki", name_kana: "コマガタ マサキ", satisfaction: nil, opinion: nil, retire_reasons: 0, unsubscribe_email_token: "037i-ef5n7V4EnPv74mtyQ", mentor_memo: nil, after_graduation_hope: nil, training_ends_on: nil, sad_streak: true, last_sad_report_id: 354780143, last_activity_at: "2014-01-01 09:00:01.000000000 +0900", hibernated_at: nil, profile_name: "駒形 真幸", profile_job: "エンジニア", profile_text: "株式会社ロッカの代表兼エンジニア。Rubyが大好きで怖話、フィヨルドブートキャンプなどを開発している...", feed_url: "https://example3.com/index.rdf", sent_student_followup_message: false, country_code: nil, subdivision_code: nil, auto_retire: true, editor: nil, other_editor: nil, invoice_payment: false, hide_mentor_profile: false, experiences: 6, tag_list: nil>
    app/components/products/product_component.html.slim:71:in `block in call'
    app/components/products/product_component.html.slim:69:in `call'
    test/components/product/product_component_test.rb:67:in `test_render_comments_count_when_there_are_comments'


rails test test/components/product/product_component_test.rb:64

調べたこと

ActiveDecorator

  • active_decorator gemによって導入される
  • app/decorators/user_decorator.rbなどのファイルで定義されている
  • ビューでよく使う表示ロジックやフォーマットを記述する
  • モデルとビューどちらにも記述できるロジックをデコレーターに記述することで、モデルとビューをスリムに保つことができる

ViewComponentのテストでのActiveDecoratorの利用

  • コンポーネントテストではActiveDecoratorは自動的には読み込まれないが、user = user.extend(UserDecorator)とすることでインスタンスからデコレーメソッドの呼び出せる
  • デコレータを呼び出せるようにしたいインスタンスが別のインスタンスのアソシエーションを介す場合は、product.user = product.user.extend(UserDecorator)とすることでデコレータメソッドを呼び出せる

エラーが発生するパターン

以下のように、コンポーネントテストでデコレーターを適用したuserproductcommentを作成した後、html側でcommentからuserを取得してデコレーターメソッドを呼び出そうとすると、undefined methodとなる。

  • コンポーネントテスト
    ※PRには未実装
 # test/components/product/product_component_test.rb
  def test_render_comments_count_when_there_are_comments
    commented_user = users(:komagata).extend(UserDecorator)
    unassigned_product = decorate_product_user(products(:product6))
    unassigned_product.comments.create!(user: commented_user, description: 'コメントを追加')
    render_inline(Products::ProductComponent.new(
      product: unassigned_product,
      is_mentor: @is_mentor,
      current_user_id: @current_user_id
    ))

    assert_selector '.a-meta', text: 'コメント(2)'
    assert_selector 'img.a-user-icon[title=?]', commented_user.icon_title
  end
  • ViewComponentのhtmlファイル
    ここのuser.icon_titleundefined methodエラーとなる

- @product.commented_users.distinct.each do |user|
a.card-list-item__user-icons-icon href=user_path(user)
img.a-user-icon title=user.icon_title alt=user.icon_title src=user.avatar_url class=role_class

対応方法

対応方法を検討しましたのでご助言お願いできますでしょうか。

  1. ViewComponentのロジック部分とActiveDecoratorはモデルとビューをスリムにするためにロジックを記述する場所という役割が被っているという認識です。ViewComponentではデコレーターメソッドは使わずにコンポーネントのロジック部分に代わりにそのロジックを記述すべきなのでしょうか?
  2. システムテストでは明示的にextend(HogeDecorator)でデコレーターを適用しないでもデコレーターメソッドが利用できます。コンポーネントテストでも同様のことが可能なのであればその方法をご教授いただけますでしょうか?

以上、お手数ですがご回答をお願いいたします。

@komagata
Copy link
Member

komagata commented Oct 1, 2024

@Shrimprin

  1. ViewComponentのロジック部分とActiveDecoratorはモデルとビューをスリムにするためにロジックを記述する場所という役割が被っているという認識です。ViewComponentではデコレーターメソッドは使わずにコンポーネントのロジック部分に代わりにそのロジックを記述すべきなのでしょうか?
  2. システムテストでは明示的にextend(HogeDecorator)でデコレーターを適用しないでもデコレーターメソッドが利用できます。コンポーネントテストでも同様のことが可能なのであればその方法をご教授いただけますでしょうか?

2でお願いします。もうちょっとだけ調べてみてください〜

@Shrimprin
Copy link
Contributor

@komagata
お疲れ様です!
Active Recordのafter_findコールバックを使ってデコレーターを適用するヘルパーを作成して、問題を対処できるようにしました。
以下のような実装方針で良いかご助言お願いできますでしょうか。

  • デコレーターを適用するヘルパー

    module DecoratorHelper
    def self.auto_decorate(model)
    model.after_find { |record| ActiveDecorator::Decorator.instance.decorate(record) }
    end
    end

  • コンポーネントテストでの使用方法
    コンポーネントテストのsetupメソッドで以下のようにして呼び出します。

require 'test_helper'
require 'supports/decorator_helper' # ヘルパーをrequireする

class Products::ProductsComponentTest < ViewComponent::TestCase
  def setup
    DecoratorHelper.auto_decorate(User) # デコレーターを適用したいモデルを引数で渡す
    # その他の処理
  end

  # テスト
end

これによりUserレコードを読み込むたびにデコレーターが適用され、テスト内で毎回extend(UserDecorator)しなくて済みます。

参考

@komagata
Copy link
Member

komagata commented Oct 5, 2024

いいと思います。ただ下記に似たコードがあるので何かしら共通化できるといいかもですね。

bootcamp/test/active_decorator_test_case.rb at main · fjordllc/bootcamp

@Shrimprin
Copy link
Contributor

@komagata
ありがとうございます。
共通化も含めてPRを作成していきます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: レビュー中
Development

No branches or pull requests

3 participants