SlideShare ist ein Scribd-Unternehmen logo
1 von 33
Downloaden Sie, um offline zu lesen
2011/10/22
   Okinawa.rb 第一回に参加した人・・・嘘
    › 発表資料はこちら
     http://www.slideshare.net/yasulab/rails-tutorial-ch12
     (謝謝 @yasulab さん)
   git が使える
   rails 3.0 (最新は 3.1)
   rails インストールして、scaffold して、r s で
    確認できる
 「rails g scaffold blog …」で CRUD出来るの
  はもう知ってるよ
 複数のモデル(テーブル)の連携部分を深く
  掘り下げて考える
 ActiveRecord::Associations の has_many
  なモデルのCRUD画面作成
 「多対多」の関係(has_many :through)
    › routing, controller, view
 隙を見て rails.vim の話やその他もろもろ...
 仕様を満たしていくまでの考え方、開発リズ
  ム
    › つっこみ歓迎w
 設計してみよう
 テニス(や卓球)のエントリ(申込)を表現
  してみよう

   サンプルプログラムのソース
    › git@github.com:naopontan/my_entry.git
 Aさんはログインして参加可能の大会の中から
  自分の好きな大会を選びます。
 次に種目(シングルス or ダブルス)を選択し
  ます。
 ダブルスの場合はパートナー一覧からパート
  ナーを選びます
 申込内容はいつでも確認できます
 Aさんはログインして参加可能の大会の中から
  自分の好きな大会を選びます。
 次に種目(シングルス or ダブルス)を選択し
  ます。
 ダブルスの場合はパートナー一覧からパート
  ナーを選びます
 申込内容はいつでも確認できます
 1つの大会は複数の種目を持つ
 1つの種目は複数の申込を持つ
 Userは複数の申込を持つ
 User と “種目”は 多対多の関係だよね
  ( user has_many events through => :entry)
大会




ユーザ
           種目




      申込
competitions
                              id
                              name



users
 id                         events
 name                        id
 is_male                     competition_id (FK)
                             name
           entries           is_male
            id
            event_id (FK)
            user_id (FK)
   r new my_entry
    › 要オプション確認: --skip-prototype, --skip-test-unit, etc…
   cd my_entry
   bundle install
   git init
   git add .
   git commit –m ‘first commit’
   rake db:migrate
   r s して http://localhost:3000/ にアクセス
   git rm public/index.html
   r g scaffold Competition name:string
        › config/routes.rb
        › test/fixtures/competitions.yml
          (RSpec の場合は
          spec/fixtures/competions.yml)
    % cat test/fixtures/competitions
    one:
     name: 招き猫オープン

    two:
     name: 閑古鳥杯

   rake db:migrate
    r g scaffold Event competition_id:integer
     name:string is_male:boolean
     % cat test/fixtures/events
     one:
      competition_id: 1
      name: MyString
      is_male: false

     two:
      ...


   「大会」と関連付けるため、上記を修正

   boolean 型の注意点
    t.boolean :is_male, :null => false, :default => true
% cat test/fixtures/events   % cat app/model/event.rb
one:                         class Event < ActiveRecord::Base
 competition: one             belongs_to :competition
 name: 18歳以下男子シングルス          end
 is_male: true

two:
 competition: one
  name: 18歳以下女子シングルス
  is_male: false

three:
  ...

   rake db:fixtures:load でテストデータを読み込み
   テストデータが多すぎるのはNG
    › 例えば users.yml は 3人~5人 ぐらいじゃね?
    › テストプログラムでパターンが足りない場合は動
      的にテストデータ生成
   rc
         › Competition.all
         › Event.all
         › Event.first
         › Event.all[0].competition
         › Event.all[0].competition.event # ←エラー
    % cat app/model/competition.rb
    class Event < ActiveRecord::Base
     has_many :events
    end

   competition has many events
     › Event.all[0].competition.event # ←Good!
     › Competition.find_by_name(‘閑古鳥杯’).events.empty?
 そもそも has_many や belong_to の実装前
  にテストから書く(ハズ)
 Event#competition_id は必須?
 大会名は必須?名前の重複は変だよね?
 種目名が1つの大会で重複もしかり
 最大文字数とかは?
 ...ということで最初は validation のOK/NGの
  テストとかになるはず...
   r g scaffold User name:string is_male:boolean
    › db/migrate/*users_rb の boolean はnull, default を忘れ
      ずに
 fixutres は男性3人、女性1人ぐらいで
 認証はプラグインで(devise, Sorcery, ...)
    › 権限も今回は無し
 r g model Entry event_id:integer
  user_id:integer
 test/fixtures/entries.yml
     % cat app/model/entry.rb
     class Entry < ActiveRecord::Base
       belongs_to :event
       belongs_to :user              % cat app/model/user.rb
     end                             class User < ActiveRecord::Base
                                      has_many :entries
                                      has_many :events, :through => :entries
 % cat app/model/event.rb            end
 class Event < ActiveRecord::Base
  has_many :entries
  has_many :users, :through => :entries
 end
competitions
                              id
                              name



users
 id                         events
 name                        id
 is_male                     competition_id (FK)
                             name
           entries           is_male
            id
            event_id (FK)
            user_id (FK)
   ログイン
       大会一覧(種目一覧)
   管理者                                利用者
    › 大会と種目の編集                          › 申込み一覧(自分の
    › 会員一覧                                み)
    › 申込み一覧                             › 申込み



         何から手をつけようか・・・
         大会は scaffold のままでほとんどOK。
 rake routes | grep events で基本を把握する
 competition has_many events を routes.rb で表現
   › events を competition にぶら下げる
   › そして、再度 rake routes | grep events

    * config/routes.rb *
    resources :users
    resources :competitions do
     resources :events, :except => [:index]
    end
       種目の一覧って2通り考えられる?
        › 1つの大会に着目したときの、それにぶら下がる一覧
        › とにかく全て(大会の域を超えて)の一覧 ←本当に必要か?
   ここでは実際のソースを見ながら解説します
    › 以下、一部抜粋

    class EventsController < ApplicationController
     before_filter :find_competition

     def new
      @event = @competition.events.new
     end
   competitions#show に種目の CRUD を挿入

<p>
 <b>Name:</b>
 <%= @competition.name %>
</p>

<table border="1">
 <tr>
   <th>Name</th>
   <th>Is male</th>
   <th></th>
   <th></th>
   <th></th>
 </tr>
 <%= render @competition.events %>
</table>
<%= link_to 'New Event', new_competition_event_path(@competition) %>
   将来、権限機能を実装するのは明らかだ
    › 基本、管理者は何でもできる
    › ということは全てのUserの申込も操作できねば
    › 申込の操作が実装できれば、後は「一般Userの申
      込も流用できそうだ」
   …ということで(私は)申込を users#show
    に実装することに決めた
<table border="1">
 <tr>
   <th>Competition</th>
   <th>Event</th>
   <th></th>
 </tr>
 <% @user.entries.each do |entry| %>
 <tr>
   <td><%= entry.event.competition.name %></td>
   <td><%= entry.event.name %></td>
   <td><%= link_to 'Cancel', entry, :confirm => 'Are you sure?', :method => :delete %></td>
 </tr>
 <% end %>
</table>


<h2>申込</h2>
<%= form_tag(entries_path, :method => :get) do %>
 <%= ("competition", "id", Competition.all.collect {|| [ .name, .id ] }) %>
 <%= hidden_field_tag :user_id, @user.id %>
 <%= submit_tag '次へ' %>
<% end %>
competitions
                              id
                              name



users
 id                         events
 name                        id
 is_male                     competition_id (FK)
                             name
           entries           is_male
            id
            event_id (FK)
            user_id (FK)
 entry.event.competition... が冗長だ
 entry から competition は1つなのに...
 API 見ると delegate メソッド発見!

    class Entry < ActiveRecord::Base
     delegate :competition, :to => :event
     ...

     entry.competition って書けた。Happy!
     この辺りは経験とか勉強の度合いで感じ取る
      › def competition; event.competition; end
 ActiveRecord::Associations の has_many
  なモデルのCRUD画面作成
 「多対多」の関係(has_many :through)
    › routing, controller, view
 隙を見て rails.vim の話やその他もろもろ...
 仕様を満たしていくまでの考え方、開発リ
  ズム
    › つっこみ歓迎w
Agile Web Development with Rails (4th edition)
http://pragprog.com/book/rails4/agile-web-development-with-rails

RailsによるアジャイルWebアプリケーション開発 第3版(注意!Rails2 です)
http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-06785-3
 たくさんありすぎ…
 @IT自分戦略研究所
    http://jibun.atmarkit.co.jp/scenter/ittrain/
    (1日1回、RSSフィードで地味にやってます)
     › ITトレメ Ruby技術者認定【Gold】試験
     › ITトレメ Rails 3 技術者認定ブロンズ試験
Okinawa.rb 第2回勉強会

Weitere ähnliche Inhalte

Ähnlich wie Okinawa.rb 第2回勉強会

Inside mobage platform
Inside mobage platformInside mobage platform
Inside mobage platformToru Yamaguchi
 
初めての Data api
初めての Data api初めての Data api
初めての Data apiYuji Takayama
 
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014Takashi Yahata
 
Rails and twitter #twtr_hack
Rails and twitter #twtr_hackRails and twitter #twtr_hack
Rails and twitter #twtr_hacki7a
 
CodeIgniterによるPhwittr
CodeIgniterによるPhwittrCodeIgniterによるPhwittr
CodeIgniterによるPhwittrkenjis
 
(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話Masanori Masui
 
広告配信現場で使うSpark機械学習
広告配信現場で使うSpark機械学習広告配信現場で使うSpark機械学習
広告配信現場で使うSpark機械学習x1 ichi
 
Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Yuji Takayama
 
WTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterWTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterMasanori Oobayashi
 
EWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/Webサービスにアクセスする
EWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/WebサービスにアクセスするEWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/Webサービスにアクセスする
EWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/WebサービスにアクセスするKiyoshi Sawada
 
VSCodeで始めるAzure Static Web Apps開発
VSCodeで始めるAzure Static Web Apps開発VSCodeで始めるAzure Static Web Apps開発
VSCodeで始めるAzure Static Web Apps開発Yuta Matsumura
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!Shohei Okada
 
Next2Dで始めるゲーム開発 - Game Development Starting with Next2D
Next2Dで始めるゲーム開発  - Game Development Starting with Next2DNext2Dで始めるゲーム開発  - Game Development Starting with Next2D
Next2Dで始めるゲーム開発 - Game Development Starting with Next2DToshiyuki Ienaga
 
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回Naoyuki Yamada
 
Spectacular Future with clojure.spec
Spectacular Future with clojure.specSpectacular Future with clojure.spec
Spectacular Future with clojure.specKent Ohashi
 
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)Hiroaki KOBAYASHI
 

Ähnlich wie Okinawa.rb 第2回勉強会 (20)

Inside mobage platform
Inside mobage platformInside mobage platform
Inside mobage platform
 
初めての Data api
初めての Data api初めての Data api
初めての Data api
 
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
 
Rails and twitter #twtr_hack
Rails and twitter #twtr_hackRails and twitter #twtr_hack
Rails and twitter #twtr_hack
 
CodeIgniterによるPhwittr
CodeIgniterによるPhwittrCodeIgniterによるPhwittr
CodeIgniterによるPhwittr
 
(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話
 
Inside Movable Type
Inside Movable TypeInside Movable Type
Inside Movable Type
 
広告配信現場で使うSpark機械学習
広告配信現場で使うSpark機械学習広告配信現場で使うSpark機械学習
広告配信現場で使うSpark機械学習
 
Ajax 応用
Ajax 応用Ajax 応用
Ajax 応用
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界
 
WTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniterWTM53 phpフレームワーク いまさらcodeigniter
WTM53 phpフレームワーク いまさらcodeigniter
 
EWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/Webサービスにアクセスする
EWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/WebサービスにアクセスするEWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/Webサービスにアクセスする
EWD 3トレーニングコース#33 ewd-xpressアプリケーションからREST/Webサービスにアクセスする
 
VSCodeで始めるAzure Static Web Apps開発
VSCodeで始めるAzure Static Web Apps開発VSCodeで始めるAzure Static Web Apps開発
VSCodeで始めるAzure Static Web Apps開発
 
Using Dancer
Using DancerUsing Dancer
Using Dancer
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
Next2Dで始めるゲーム開発 - Game Development Starting with Next2D
Next2Dで始めるゲーム開発  - Game Development Starting with Next2DNext2Dで始めるゲーム開発  - Game Development Starting with Next2D
Next2Dで始めるゲーム開発 - Game Development Starting with Next2D
 
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回
 
Spectacular Future with clojure.spec
Spectacular Future with clojure.specSpectacular Future with clojure.spec
Spectacular Future with clojure.spec
 
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
 

Okinawa.rb 第2回勉強会

  • 2. Okinawa.rb 第一回に参加した人・・・嘘 › 発表資料はこちら http://www.slideshare.net/yasulab/rails-tutorial-ch12 (謝謝 @yasulab さん)  git が使える  rails 3.0 (最新は 3.1)  rails インストールして、scaffold して、r s で 確認できる
  • 3.  「rails g scaffold blog …」で CRUD出来るの はもう知ってるよ  複数のモデル(テーブル)の連携部分を深く 掘り下げて考える
  • 4.  ActiveRecord::Associations の has_many なモデルのCRUD画面作成  「多対多」の関係(has_many :through) › routing, controller, view  隙を見て rails.vim の話やその他もろもろ...  仕様を満たしていくまでの考え方、開発リズ ム › つっこみ歓迎w
  • 5.  設計してみよう  テニス(や卓球)のエントリ(申込)を表現 してみよう  サンプルプログラムのソース › git@github.com:naopontan/my_entry.git
  • 6.  Aさんはログインして参加可能の大会の中から 自分の好きな大会を選びます。  次に種目(シングルス or ダブルス)を選択し ます。  ダブルスの場合はパートナー一覧からパート ナーを選びます  申込内容はいつでも確認できます
  • 7.  Aさんはログインして参加可能の大会の中から 自分の好きな大会を選びます。  次に種目(シングルス or ダブルス)を選択し ます。  ダブルスの場合はパートナー一覧からパート ナーを選びます  申込内容はいつでも確認できます
  • 8.  1つの大会は複数の種目を持つ  1つの種目は複数の申込を持つ  Userは複数の申込を持つ  User と “種目”は 多対多の関係だよね ( user has_many events through => :entry)
  • 9. 大会 ユーザ 種目 申込
  • 10. competitions id name users id events name id is_male competition_id (FK) name entries is_male id event_id (FK) user_id (FK)
  • 11. r new my_entry › 要オプション確認: --skip-prototype, --skip-test-unit, etc…  cd my_entry  bundle install  git init  git add .  git commit –m ‘first commit’  rake db:migrate  r s して http://localhost:3000/ にアクセス  git rm public/index.html
  • 12. r g scaffold Competition name:string › config/routes.rb › test/fixtures/competitions.yml (RSpec の場合は spec/fixtures/competions.yml) % cat test/fixtures/competitions one: name: 招き猫オープン two: name: 閑古鳥杯  rake db:migrate
  • 13. r g scaffold Event competition_id:integer name:string is_male:boolean % cat test/fixtures/events one: competition_id: 1 name: MyString is_male: false two: ...  「大会」と関連付けるため、上記を修正  boolean 型の注意点 t.boolean :is_male, :null => false, :default => true
  • 14. % cat test/fixtures/events % cat app/model/event.rb one: class Event < ActiveRecord::Base competition: one belongs_to :competition name: 18歳以下男子シングルス end is_male: true two: competition: one name: 18歳以下女子シングルス is_male: false three: ...  rake db:fixtures:load でテストデータを読み込み
  • 15. テストデータが多すぎるのはNG › 例えば users.yml は 3人~5人 ぐらいじゃね? › テストプログラムでパターンが足りない場合は動 的にテストデータ生成
  • 16. rc › Competition.all › Event.all › Event.first › Event.all[0].competition › Event.all[0].competition.event # ←エラー % cat app/model/competition.rb class Event < ActiveRecord::Base has_many :events end  competition has many events › Event.all[0].competition.event # ←Good! › Competition.find_by_name(‘閑古鳥杯’).events.empty?
  • 17.  そもそも has_many や belong_to の実装前 にテストから書く(ハズ)  Event#competition_id は必須?  大会名は必須?名前の重複は変だよね?  種目名が1つの大会で重複もしかり  最大文字数とかは?  ...ということで最初は validation のOK/NGの テストとかになるはず...
  • 18. r g scaffold User name:string is_male:boolean › db/migrate/*users_rb の boolean はnull, default を忘れ ずに  fixutres は男性3人、女性1人ぐらいで  認証はプラグインで(devise, Sorcery, ...) › 権限も今回は無し
  • 19.  r g model Entry event_id:integer user_id:integer  test/fixtures/entries.yml % cat app/model/entry.rb class Entry < ActiveRecord::Base belongs_to :event belongs_to :user % cat app/model/user.rb end class User < ActiveRecord::Base has_many :entries has_many :events, :through => :entries % cat app/model/event.rb end class Event < ActiveRecord::Base has_many :entries has_many :users, :through => :entries end
  • 20. competitions id name users id events name id is_male competition_id (FK) name entries is_male id event_id (FK) user_id (FK)
  • 21. ログイン  大会一覧(種目一覧)  管理者  利用者 › 大会と種目の編集 › 申込み一覧(自分の › 会員一覧 み) › 申込み一覧 › 申込み 何から手をつけようか・・・ 大会は scaffold のままでほとんどOK。
  • 22.  rake routes | grep events で基本を把握する  competition has_many events を routes.rb で表現 › events を competition にぶら下げる › そして、再度 rake routes | grep events * config/routes.rb * resources :users resources :competitions do resources :events, :except => [:index] end  種目の一覧って2通り考えられる? › 1つの大会に着目したときの、それにぶら下がる一覧 › とにかく全て(大会の域を超えて)の一覧 ←本当に必要か?
  • 23. ここでは実際のソースを見ながら解説します › 以下、一部抜粋 class EventsController < ApplicationController before_filter :find_competition def new @event = @competition.events.new end
  • 24. competitions#show に種目の CRUD を挿入 <p> <b>Name:</b> <%= @competition.name %> </p> <table border="1"> <tr> <th>Name</th> <th>Is male</th> <th></th> <th></th> <th></th> </tr> <%= render @competition.events %> </table> <%= link_to 'New Event', new_competition_event_path(@competition) %>
  • 25. 将来、権限機能を実装するのは明らかだ › 基本、管理者は何でもできる › ということは全てのUserの申込も操作できねば › 申込の操作が実装できれば、後は「一般Userの申 込も流用できそうだ」  …ということで(私は)申込を users#show に実装することに決めた
  • 26. <table border="1"> <tr> <th>Competition</th> <th>Event</th> <th></th> </tr> <% @user.entries.each do |entry| %> <tr> <td><%= entry.event.competition.name %></td> <td><%= entry.event.name %></td> <td><%= link_to 'Cancel', entry, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <h2>申込</h2> <%= form_tag(entries_path, :method => :get) do %> <%= ("competition", "id", Competition.all.collect {|| [ .name, .id ] }) %> <%= hidden_field_tag :user_id, @user.id %> <%= submit_tag '次へ' %> <% end %>
  • 27. competitions id name users id events name id is_male competition_id (FK) name entries is_male id event_id (FK) user_id (FK)
  • 28.  entry.event.competition... が冗長だ  entry から competition は1つなのに...  API 見ると delegate メソッド発見! class Entry < ActiveRecord::Base delegate :competition, :to => :event ...  entry.competition って書けた。Happy!  この辺りは経験とか勉強の度合いで感じ取る › def competition; event.competition; end
  • 29.
  • 30.  ActiveRecord::Associations の has_many なモデルのCRUD画面作成  「多対多」の関係(has_many :through) › routing, controller, view  隙を見て rails.vim の話やその他もろもろ...  仕様を満たしていくまでの考え方、開発リ ズム › つっこみ歓迎w
  • 31. Agile Web Development with Rails (4th edition) http://pragprog.com/book/rails4/agile-web-development-with-rails RailsによるアジャイルWebアプリケーション開発 第3版(注意!Rails2 です) http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-06785-3
  • 32.  たくさんありすぎ…  @IT自分戦略研究所 http://jibun.atmarkit.co.jp/scenter/ittrain/ (1日1回、RSSフィードで地味にやってます) › ITトレメ Ruby技術者認定【Gold】試験 › ITトレメ Rails 3 技術者認定ブロンズ試験