関西Ruby会議08に参加した

6月28日(土)に京都で開催された関西Ruby会議08に参加してきました。

2年前の大阪Ruby会議03に参加して以来の関西圏でのカンファレンス参加でした。 開催後1週間が経っていますが、今振り返っても参加できてよかったな〜と温かい気持ちになる素敵な場でした!

発表の感想

「富岳」と研究者をRubyでつなぐ:シミュレーション管理ツールOACIS

スライドは公開されてなさそう? 研究機関の場で Ruby が活用されている事例でとても興味深い発表でした。

「1ヶ月でWebサービスを作る会」で出会った rails new、そして今に至る rails new

speakerdeck.com

個人開発でローンチするまでの流れを実体験をもとに丁寧に紹介されていて、自分もやるぞ!と背中を押してくれる発表でした。 サービスを個人で運用するにはサーバー代など費用が発生する訳で、その辺りについても工夫された点など言及されていて個人開発のリアルが詰まっていました。

ふだんのWEB技術スタックだけでアート作品を作ってみる

speakerdeck.com

個々のアナログ時計の集合がゆっくり時間をかけてデジタル時計としての表現に変わる様子がとても素敵な作品でした。 また、Vue.js 版、Rails版、Wasm版と技術構成を変えてトライされていた点について、全く分野は違うのですが私も自作ブログを技術構成を変えて複数作ったりしているため、同じものでも構成が違うと考える点が変わるんだよな〜とか聞きながら一人で共感していました。

発表後にソースコードを見たいです!とお声がけをしたところ、その日のうちに公開してくださったため速攻スターをつけました! 実装を参考にさせていただきつつ、自分もRailsでクリエイティブコーディングをやってみたくなっています。

分散オブジェクトで遊ぼう!〜dRubyで作るマルチプレイヤー迷路ゲーム〜

speakerdeck.com

dRuby は RubyKaigi で興味を持ちつつ自分自身ではまだ触れられていない技術だったため、実際に迷路ゲームを開発した体験談を聞くことができ、どういうことができて難しい部分は何だったのかを具体的に知ることができました。 ゲーム全体のアーキテクチャなども丁寧に解説されていて分かりやすかったです!

Rubyで世界を作ってみる話

こちらもスライドは公開されてなさそう? 予想ができない発表内容で聞いていてとても面白かったです。 また、スライドに散りばめられた松田さんのコードが切れ味が良くてかっこよかった。

Regional.rb and the Kyoto City

これは現地で聞くことができてとてもよかったと思えたセッションでした。

私自身、コミュニティをやっていて共感する部分がたくさんあったのと、ここでの話を聞いたことでしんめ.rbの取り組み方をちょっと見直してみようと迷っていたところから一歩踏み出す勇気をもらえました。

まとめ

今回、関西Ruby会議08に参加して一つ気がついたことがあって、私は「何を」作るかよりも「どう」作るかに今はすごく興味があるんだなということを自覚しました。 それもあって、自作ブログを技術構成を変えて作り続けたりできてるんだろうなと実感して一人納得していました。 ただ、発表を通して作りたいものを実現していく楽しさも思い出すことができ、「何をどう」作るかという部分を大切にしながら、今後も個人開発を楽しんでいきたいなと思いました。

運営・発表者の皆様、素敵なカンファレンスの場をありがとうございました! 来年の滋賀も参加するぞ〜!

しんめ.rb の開催について

2024年3月より開催を始めたしんめ.rb ですが、2025年7月以降は毎週開催をやめて『不定期開催』とすることにしました・・・!

7月は開催を行わず、8月以降は月2回程度を目安にこれまで通りオンラインで開催しようと考えています。

東京Ruby会議12や関西Ruby会議08に参加した際に地域rbを続けるコツは「無理しない」ことが挙げられていました。最近の私に関してはしんめでやりたいことは色々あるものの準備にそこまで時間をかけられなかったりで、自分の中に準備不足感が蓄積していたり、うまく進行できていないな〜という気持ちがあり、少し「無理」が生じ始めていました。

コミュニティを終わりにするかも考えたのですが、しんめを通じて関東圏以外の Rubyist たちと繋がることができ、カンファレンスなどのイベント参加がより一層楽しくなったこと、みんなでモブプロをしたり情報交換をする時間も大好きなことから、終わらせるのではなく開催頻度を減らして継続することにしました!

コミュニティを自分で主催していると失敗をしたり反省点は尽きず、課題もたまっていってしまったりします。 その一方で主催しているからこそ得られる良さもたくさんあります。

自分が忙しかったり、疲れていたりするとどうしても考えがネガティブ寄りに傾きがちなため、そいう時こそ無理をしないが大事だな〜1年間の開催を経て私自身も学ぶことができました。

8月以降は開催をする場合、曜日はこれまで通り月曜開催としますが、開始時間は20時からにしようと考えています(開始時間は21時からのままにするかもしれないため、次回開催日を決める際に告知します!)。

これからも RubyRails ともっと仲良くなりたい!みんなでワイワイ楽しく勉強する場としてしんめ.rb を育てていけたらと思います。

1ヶ月お休みをいただきますが、8月から改めてよろしくお願いします🌱

【フロントエンド学習記録】Ember.jsでブログ投稿画面のプレビューをできるようにする

前回はブログ記事をマークダウンで書けるようにする実装を見ていきました。

maimux2x.hatenablog.com

次は記事中の任意の場所に画像を埋め込めるようにする部分を見ていくと書いてたのですが、先にEmber.jsでブログ投稿画面のプレビューをできるようにする部分の実装を見ていきたいと思います。

画像のようにタブがあって、ブログ記事を書く部分とプレビューできる部分を作りました。

Rails のみでプレビューをできるようにする場合、Hotwire で TurboFrames や Stimulus を使って実装する形になると思うのですが、Ember.js ではすでにブログ記事を表示する役割を担っているコンポーネントがあるため、実はそれを再利用すればすぐに実装することができます。

そのため、やったこととしてはブログ投稿画面の hbs ファイルを Bootstrap のナビゲーションコンポーネントとタブJavaScriptプラグインを使ってタブを切り替えられるようにして、投稿用のタブに元々あったコードを移して、プレビュー用のタブでブログ記事を表示するための Post コンポーネントを呼び出す対応のみです!

getbootstrap.jp

<!-- web/app/components/post-form.hbs -->

<ul class="nav nav-tabs mb-3" id="postFormTab" role="tablist">
  <li class="nav-item" role="presentation">
    <button class="nav-link active" id="home" data-bs-toggle="tab" data-bs-target="#home-pane" type="button" role="tab" aria-controls="home-pane" aria-selected="true">Form</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="preview" data-bs-toggle="tab" data-bs-target="#preview-pane" type="button" role="tab" aria-controls="preview-pane" aria-selected="false">Preview</button>
  </li>
</ul>
<div class="tab-content" id="postFormTabContent">
  <div class="tab-pane fade show active" id="home-pane" role="tabpanel" aria-labelledby="form-tab">
    <!-- 元々あった投稿用のフォームの実装 -->
  <div class="tab-pane fade" id="preview-pane" role="tabpanel" aria-labelledby="preview-tab">
    <Post @post={{@post}} /> <!-- Postコンポーネントを呼び出す -->
  </div>
</div>

まとめ

フロントエンド側のフレームワークコンポーネント化されているパーツの再利用が便利だな〜と感じた瞬間でした。

また、Bootstrap もWeb サービスで頻繁に利用される UI を実現するためのコンポーネントなどがたくさんあって、同様に便利だなと思ったのともっと使いこなせるようになりたいと思いました。

順番を入れ替えたため、次回に記事中の任意の場所に画像を埋め込めるようにする実装を見ていきます!

【フロントエンド学習記録】マークダウン形式でブログを投稿できるようにする

前回はブログに複数枚の画像を添付する実装を見ていきました。

今回は画像をブログ本文の任意の場所に挿入できるようにする前準備としてマークダウンで記事を書けるようにしていく実装を見ていきます。

マークダウン形式で記事を書けるようにするには、現段階では投稿フォーム側で特に実装を変更する箇所はありません。対応が必要なのはブログ本文を描画する側の実装です。

maimux2x.hatenablog.com

実装にあたり Marked というライブラリを使いました。

github.com

Marked を利用することでマークダウン形式のテキストを HTML に変換することができます。 利用する上では README にも記載がある通り、Marked のみでは HTML をサニタイズすることができないため、別のライブラリと併用する必要があります。

github.com

今回はMarked の README に記載されていた sanitize-html を使ってみました。

これらを利用して本文を引数に取り HTML への変換とサニタイズ、HTML としてレンダリングするためのアクションを用意します。

// web/app/components/post.js

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { marked } from 'marked';
import { htmlSafe } from '@ember/template';
import sanitizeHtml from 'sanitize-html';

export default class PostComponent extends Component {
  @action
  renderMarkdown(body) {
    return htmlSafe(sanitizeHtml(marked.parse(body)));
  }
}

Marked と sanitize-html を使ってブログ本文をマークダウンから HTML へ変換し、サニタイズしている部分が sanitizeHtml(marked.parse(body) です。そして、変換された HTML を Ember.js へ HTML としてレンダリングすることを伝えるための関数が htmlSafe() の部分です。

このアクションを以下のように使用することで、マークダウン形式で保存されているブログ本文が適切に変換された結果として描画することができます。

<!-- web/app/components/post.hbs -->

<div class="card mb-3">
  <div class="card-body">
    <h2 class="card-title">
      {{#if @link}}
        <LinkTo @route="posts.show" @model={{@post.id}}>{{@post.title}}</LinkTo>
      {{else}}
        {{@post.title}}
      {{/if}}
    </h2>
    <div class="card-text">{{this.renderMarkdown @post.body}}</div> <!-- @post.body をアクションに渡す -->
    {{#each @post.image_urls as |url|}}
      <img src={{url}} alt="" class="img-fluid">
    {{/each}}
  </div>
</div>

これで実装完了です!

まとめ

最低限のマークダウンでブログ本文を書くようなユースケースであれば、ライブラリのおかげでスムーズに対応できることが分かりました。

投稿フォーム側でできることを増やしていこうとすると、実装上色々考えないといけない部分が出てきそうです。次はその事例の一つとして画像をマークダウン本文内の任意の位置に挿入できるようにする部分の実装を見ていきたいと思います!

【フロントエンド学習記録】ActiveStorageを使ってブログ記事に画像を複数枚添付できるようにする

前回、ActiveStorage を使って画像を1枚添付するやり方について見ていきました。

maimux2x.hatenablog.com

今回はその続きで、ActiveStorage を使って複数枚の画像を添付できるようにしていきたいと思います。

まず、Rails 側を修正していきます。

# app/models/post.rb

class Post < ApplicationRecord
  has_many_attached :images # 変更

  # 省略

  validates :images, content_type: [ "image/png", "image/jpeg" ]
end

前回、モデルにバリデーションを指定していなかったため、アップロードできるファイルを pngjpeg のみに限定しました。

# app/controllers/posts_controller.rb

class PostsController < ApplicationController
# 省略

private

  def post_params
    params.expect(post: [ :title, :body, images: [] ]) # image を images: [] に修正
  end
end
# app/views/posts/_post.json.jb

{
  id:         post.id,
  created_at: post.created_at,
  title:      post.title,
  body:       post.body,
  image_urls: post.images.map { rails_blob_url(it) } # 修正 / 画像が添付されていない場合は空の配列
}

続いてEmber.js 側の修正です。ベースはできているため複数枚の画像を選択してリクエストできるようにしていきます。

// web/app/components/post-form.js

import Component from '@glimmer/component';
import { DirectUpload } from '@rails/activestorage/src/direct_upload';
import { action } from '@ember/object';

export default class PostFormComponent extends Component {
  @action
  uploadImage(e) {
    this.args.post.images = [];

    for (const file of e.target.files) {
      const upload = new DirectUpload(
        file,
        'http://localhost:3000/rails/active_storage/direct_uploads',
        {},
      );

      upload.create((error, blob) => {
        if (error) {
          console.error(error.message);
        } else {
          this.args.post.images.push(blob.signed_id);
        }
      });
    }
  }
}

今回は複数枚の画像を選択してそれぞれの signed_id を Rails 側へリクエストする必要があります。そのために this.args.post.images の空の配列を用意して FileList を反復処理しながら this.args.post.images へ signed_id を詰めていきます。

そしてそれをリクエスト時に送るようにします。

// web/app/controllers/admin/posts/new.js

import Controller from '@ember/controller';
import { action } from '@ember/object';
import { service } from '@ember/service';
export default class AdminPostsNewController extends Controller {
  @service router;
  @service toast;
  @service session;
  @action
  async createPost(event) {
    event.preventDefault();
    const response = await fetch('http://localhost:3000/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${this.session.token}`,
      },
      body: JSON.stringify({
        post: {
          title: this.model.title,
          body: this.model.body,
          images: this.model.images, // images に修正
        },
      }),
    });

ロジック部分はこれで修正できました!

今度は画像選択ボタンの見た目を整えていきます。

現在の画像選択ボタンはこんな見た目です。

<input type="file" id="file" name="file" multiple {{on "change" this.uploadImage}} />

以下のように input タグに hidden 属性を付け、label タグの for 属性で hidden にした input を参照することで、bootstrap のボタンデザインを適用した状態でファイル選択ができます。

また、Rails 側でバリデーションを追加したためエラーがあった場合の対応もしています。

<!-- web/app/components/post-form.hbs -->

<input type="file" id="file" name="file" class="{{if @post.errors.images "is-invalid"}}" multiple {{on "change" this.uploadImage}} hidden />
<label for="file" class="btn btn-outline-primary">
  Choose image
</label>
{{#each @post.errors.images as |error|}}
  <div class="invalid-feedback">
    {{error}}
  </div>
{{/each}}

画像選択ボタンにデザインを当てたことで、何枚の画像を選択しているのかが表示されなくなっているのですが、今回は最終的にマークダウンで任意の箇所に画像を挿入できることを目指しているため、この状態で問題ありません。

後は画像の表示を複数枚対応に修正していきます。

<!-- web/app/components/post.hbs -->

<div class="body card-text">
  {{@post.body}}
  {{#each @post.image_urls as |url|}}
    <img src={{url}} alt="" class="img-fluid">
  {{/each}}
</div>

これで複数枚の画像を添付できるようにする修正が完了です!

まとめ

いきなり複数枚画像の添付を目指さず、まずは1枚添付できることを確認して修正をしたことで複数枚対応が進めやすくなりました。

次回はブログ記事の投稿をマークダウンでできるようにしていく部分を見ていきます。

【フロントエンド学習記録】ActiveStorageを使ってブログ記事に画像を1枚添付できるようにする

今回は Rails と Ember.js で作っているブログアプリで記事を作成・更新する際に画像を添付できるようにしていきたいと思います。

最終的には記事をマークダウンで書いて、その中の任意の箇所に画像を挿入できるようにすることを目指していて、その前段階の実装です。

前回はトーストメッセージの実装について書きました。

maimux2x.hatenablog.com

ActiveStorageを使って画像を1枚添付できるようにする

画像添付にあたっては Rails の ActiveStorage を使っていきます。

railsguides.jp

ここでは ActiveStorage の細かな導入手順には触れません。 画像を複数枚添付できるようにすることを目指しますが、まずは1枚だけ添付できるようにすることからやっていきます。

まず、Rails 側の実装を進めていきます。 モデルとコントローラを以下のように修正します。

# app/models/post.rb

class Post < ApplicationRecord
  has_one_attached :image # 追加

  validates :title, presence: true
  validates :body, presence: true
end
# app/controllers/posts_controller.rb

# 省略

private

  def post_params
    params.expect(post: [ :title, :body, :image ]) # :image を追加
  end
end

続いて、Ember.js 側の実装を見ていきます。

ブログの新規投稿画面と更新画面に画像添付のボタンが出るようにします。 input タグに設定している action の詳細は後ほど確認します。

<!-- web/app/components/post-form.hbs -->

<form {{on "submit" @onSubmit}}>

<!-- 省略 -->
  
  <button type="submit" class="btn btn-primary me-2">{{@submitLabel}}</button>
  <!-- 以下を追記 -->
  <input type="file" id="file" name="file" multiple {{on "change" this.uploadImage}} />
</form>

これでひとまず画像添付のためのボタンが表示されるようになりました。

これだけでは Rails 側へ画像添付のリクエストを送れないため、そちらの実装も見ていきます。

www.npmjs.com

その際、npm として提供されている ActiveStorage のパッケージを利用します。ダイレクトアップロード機能を使ってEmber.jsから画像ファイルをサーバーに直接送信できるようにしていきます。 ここでちょっと困ったのがどのようにダイレクトアップロードの機能を使えばいいかが具体的に書かれたドキュメントが見つけられませんでした...。

そのため、ActiveStorage の実装を確認して、ダイレクトアップロードに必要な処理をEmber.js側で実装していきます。

// node_modules/@rails/activestorage/src/direct_upload.js

import { FileChecksum } from "./file_checksum"
import { BlobRecord } from "./blob_record"
import { BlobUpload } from "./blob_upload"

let id = 0

export class DirectUpload {
  constructor(file, url, delegate, customHeaders = {}) {
    this.id = ++id
    this.file = file
    this.url = url
    this.delegate = delegate
    this.customHeaders = customHeaders
  }

  create(callback) {
    FileChecksum.create(this.file, (error, checksum) => {
      if (error) {
        callback(error)
        return
      }

      const blob = new BlobRecord(this.file, checksum, this.url, this.customHeaders)
      notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr)

      blob.create(error => {
        if (error) {
          callback(error)
        } else {
          const upload = new BlobUpload(blob)
          notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr)
          upload.create(error => {
            if (error) {
              callback(error)
            } else {
              callback(null, blob.toJSON())
            }
          })
        }
      })
    })
  }
}

function notify(object, methodName, ...messages) {
  if (object && typeof object[methodName] == "function") {
    return object[methodName](...messages)
  }
}

ダイレクトアップロードをしたいため、node_modules/@rails/activestorage/src/direct_upload.js の実装内容を見ていきます。 まず、Ember.js 側で DirectUpload オブジェクトを作成するために最低限必要な引数を確認します。 constructor の実装を見てみると customHeaders = {} は省略可能で、file, url, delegate を引数として指定する必要があることが分かります。delegate について簡単に調べてみると、これを使用するとアップロードの際の進捗や独自のエラーハンドリングなどをフックすることが可能なようです。今回はそこまでは求めないため、{} を引数にして省略することにします。Ember.js側で考慮しなければいけない引数はfile, urlの2つになりそうです。

constructor(file, url, delegate, customHeaders = {}) {
    this.id = ++id
    this.file = file
    this.url = url
    this.delegate = delegate
    this.customHeaders = customHeaders
  }

また、node_modules/@rails/activestorage/src/direct_upload.js の実装から作成した DirectUpload オブジェクトに対して、createerrorを第1引数、blobを第2引数にもつコールバック関数を渡して呼び出せば良さそうなことが分かりました。

これらを考慮して Ember.js 側で画像添付をする際の action を実装していきます。

// app/components/post-form.js

import Component from '@glimmer/component';
import { DirectUpload } from '@rails/activestorage/src/direct_upload';
import { action } from '@ember/object';

export default class PostFormComponent extends Component {
  @action
  uploadImage(e) {
    const upload = new DirectUpload(
      e.target.files[0],
      'http://localhost:3000/rails/active_storage/direct_uploads',
      {},
    );

    upload.create((error, blob) => {
      this.args.post.image = blob.signed_id;
    });
  }
}

DirectUpload オブジェクトの作成部分を見ていきます。先ほど調べた通り、file, urlを指定して、delegate は省略するようにしています。

fileを指している e.target.files の実態は FileList オブジェクトです。HTMLの <input type="file"> 要素でファイルが選択されると、イベントオブジェクト ee.target.files プロパティには FileList オブジェクトが格納されます。

console.log(e.target.files) を仕込んでブラウザーの開発者ツールで確認してみます。

FileList オブジェクトは配列のように扱うことが可能なため、 e.target.files[0] とすることで選択されたファイルにアクセスすることができます。

url に指定しているのはActive Storageが提供するアップロード用のエンドポイントです。※とりあえず localhost:3000 をベタ書きしています。

そして先ほど確認したcreate の呼び出し部分で、this.args.post.imagblob.signed_id をセットします。こうすることで、フォーム送信時に image パラメータとしてこの signed_id が送信され、Rails側で has_one_attached :image に添付されるようになります。

image パラメータはブログ記事の新規作成と更新時に一緒に送られるように修正します。

// web/app/controllers/admin/posts/new.js

import { action } from '@ember/object';
import { service } from '@ember/service';
export default class AdminPostsNewController extends Controller {
  @service router;
  @service toast;
  @service session;
  @action
  async createPost(event) {
    event.preventDefault();
    const response = await fetch('http://localhost:3000/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${this.session.token}`,
      },
      body: JSON.stringify({
        post: {
          title: this.model.title,
          body: this.model.body,
          image: this.model.image, // 追加
        },
      }),
    });

これで Ember.js から Rails に対して画像の情報を一緒に送ることができるようになりました!

最後に画像の表示について見ていきます。

まず、Rails から画像の表示に必要な情報(URL)を提供するように修正します。

// app/views/posts/_post.json.jb

{
  id:         post.id,
  created_at: post.created_at,
  title:      post.title,
  body:       post.body,
  image_url:  post.image.attached? ? rails_blob_url(post.image) : nil
}

画像は添付されていない場合もあるため三項演算子で添付されている場合だけ、rails_blob_url ヘルパーでURLを作成しています。

rails_blob_url ヘルパーで作成される URL は rails c でコンソールからも確認できます。

> blob = ActiveStorage::Blob.last
> include Rails.application.routes.url_helpers
> rails_blob_path(blob, only_path: true)
=> "/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsiZGF0YSI6ODQsInB1ciI6ImJsb2JfaWQifX0=--85409ae096792a2a9aa26383c7dc0d2dbc861d46/food_konbini_onigiri.png"
> blob.signed_id
=> "eyJfcmFpbHMiOnsiZGF0YSI6ODQsInB1ciI6ImJsb2JfaWQifX0=--85409ae096792a2a9aa26383c7dc0d2dbc861d46"

ここまで何度か signed_id というものが登場しましたが、これはActiveStorageのBlobのidを暗号化したものです。

また、余談になりますがブラウザから画像を選択した時点で ActiveStorage::Blob は作成されるため、保存・更新前の段階でも rails c でコンソールから確認が可能です。 今回のようにフロント側が Rails ではない場合にちゃんと ActiveStorage::Blob が作成されているかを段階を追って確認できます。

説明が長くなってしまいましたが、あとは image_url を使って画像を表示させるだけです。

<!-- web/app/components/post.hbs -->

<div class="body card-text">
    {{@post.body}}
    {{#if @post.image_url}}
      <img src={{@post.image_url}} alt="">
    {{/if}}
</div>

まとめ

Ember.js と Rails で ActiveStorage を使って画像を1枚添付するやり方を見てきました。

実装をしてみて、direct_upload.js の内容を確認した部分が面白くて勉強になりました。ActiveStorage への理解もだいぶ深まったと思います。

次は第2弾として ActiveStorage で複数枚の画像を添付できるようにする部分をまとめたいと思います。

しんめ.rbの1年をふりかえって&今後について

しんめ.rb は今年の3月で初開催から、1年が経ちました。 ここまで継続できたのは参加してくれているメンバーの皆さんのおかげです! この場を借りて「いつも、ありがとうございます!!!」をこれまで参加してくれた全員にお伝えしたいです。

1年経ったので、どんなことをやってきたか簡単にふりかえりたいと思います。

N + 1 勉強会

N + 1 が発生する状況を意図的に作り、joins, eager_load, preload, includes を用いてどんな違いがあるかをみんなで確認していきました。

RailsCRUD なアプリを作るモブプロ

github.com

Comic appと題して漫画のタイトルと出版社、著者を登録できるアプリをモブプロで作りました。

モブプロの初回時、私が rails newするディレクトリを間違えてぷち公開事故な状況になったのですが、モブプロ参加メンバーが一緒に次のステップを考えて取り組んでくれたおかげで事なきを得たのが思い出深い&反省案件でした。

Exercism の Ruby の問題に取り組むモブプロ

exercism.org

Exercism という無料で取り組めるプログラミング学習サイトの Ruby の問題をモブプロ形式でみんなで解いていくことを定期的に行いました。

初めに書いたコードを他の書き方がないか調べながら修正したり、実装で詰まったときにみんなでどうコードを書くか話し合ったり、勉強にもなるしワイワイしながらコードを書ける楽しい時間でした。

Rails 1.0 のコードリーディング

github.com

Rails 1.0 のコードリーディングも背伸び回ではありましたが、取り組んで良かったことの一つです。

一人では途中で諦めてしまいそうなコードリーディングも参加者同士で会話したり調べながら読み進めることで読むと決めていた個所はやり切ることができました。

Hotrails のチュートリアル

www.hotrails.dev

Hotrails でチュートリアルに沿って Hotwire を学ぶモブプロに取り組みました。 Turbo への理解深めることができたのと、仕事にも取り入れられそうな Rails のテクニックがさりげなく紹介されていたりして勉強になる部分がたくさんありました。

コードの理解が曖昧でうまく説明できない部分があったり、モブプロを通じて会話しながら取り組むことで自分自身が何を分かってないのかを整理することもできたなと感じています。

座談会

モブプロとは別にテーマを決めて雑談する座談会も複数回開催しました。

カンファレンス前は発表内容の予習をしたり、別の回では読んだり気になっている技術書を共有したり、不定期で行っています。

RubyKaigi 2025 ランチミートアップ

RubyKaigi 2025 では初めてオフラインミートアップを開催しました。 普段はオンライン上で集まっているため、みんなで直接会える機会は貴重ですごく嬉しかった回です。

今後について

これからもみんなで手を動かして学びを共有したり、RubyRails をもっと深掘りしたい人同士で交流できる場を作っていけるように引き続きモブプロと座談会を主軸にやっていきたいと考えています。

コミュニティを自分で主催していると今日はうまく進行できなかったな...質問に対して曖昧に答えてしまったな...という反省点はたくさん出てきて凹むこともあるのですが、それ以上に参加者同士で質問しあったり調べたり会話しながら RubyRails についてわいわいと話せる勉強会の時間がとても好きです。

「勉強会」であることに参加のハードルを感じている方もいるかもしれませんが、テーマに沿って勉強することと同じくらい(それ以上かも)参加者同士の会話など交流を大切に取り組んでいます。 気になるテーマの回があれば、気軽に覗きにきていただけると嬉しいです。

2年めのしんめ.rbもよろしくお願いします!