プロジェクト

全般

プロフィール

機能 #81

未完了

Redmine 4.0でglossary pluginを動くようにする

高橋 徹 さんが6年以上前に追加. 約6年前に更新.

ステータス:
進行中
優先度:
通常
担当者:
-
カテゴリ:
Redmine
対象バージョン:
-
開始日:
2018/04/22
期日:
進捗率:

50%

予定工数:

説明

Redmine 4.0(2018-04-22時点で開発中)でglossary pluginが動くかどうかを確かめるため、開発ブランチにglossary pluginを入れてみたところ、エラーとなった(次の日記参照)。

redmine trunkを落としてglossary pluginが動くか試してみる

Redmine 4.0で動かすための修正方法(最低限)を調査し、動作するための修正を見出す。

終了条件:動作するための修正を見出す。あきらめる。


関連するチケット 4 (1件未完了3件完了)

関連している 機能 #40: Redmine 3.0でglossary pluginを動くようにする終了高橋 徹2015/03/21

操作
関連している 機能 #75: Redmine Glossary プラグインを一から作成する進行中高橋 徹2019/10/19

操作
関連している 機能 #83: Redmine Glossaryプラグインをリファクタリングする却下高橋 徹2018/07/16

操作
関連している 機能 #95: Redmine 4.xに対応するRedmine Glossaryプラグインを、旧バージョンのデータベースを引き継ぎ、且つコードをきれいに再構築する却下高橋 徹2019/10/19

操作

高橋 徹 さんが6年以上前に更新

  • 関連している 機能 #40: Redmine 3.0でglossary pluginを動くようにする を追加

高橋 徹 さんが6年以上前に更新

  • 関連している 機能 #75: Redmine Glossary プラグインを一から作成する を追加

高橋 徹 さんが6年以上前に更新

rake redmine:plugins:migrate すると次のエラー

NoMethodError: undefined method `alias_method_chain' for ActionView::Helpers::AssetTagHelper:Module
Did you mean?  alias_method
plugins/redmine_glossary/lib/glossary_asset_tag_helper_patch.rb:20:in `<module:AssetTagHelper>'

alias_method_chainはRails 5.1では削除されていおり、Module#prepend で書き換えろとあります。ところが、書き換え方はさっぱり不明(alias_method_chainもよく分からず)。

まずは理解しないまま当てずっぽうな変更を実施。

--- a/lib/glossary_asset_tag_helper_patch.rb                          
+++ b/lib/glossary_asset_tag_helper_patch.rb                          
@@ -1,8 +1,8 @@                                                       
 module ActionView                                                    
   module Helpers                                                     
-    module AssetTagHelper                                            
-      def javascript_include_tag_with_glossary(*sources)             
-        out = javascript_include_tag_without_glossary(*sources)      
+    module AssetTagHelperIncludeTag                                  
+      def javascript_include_tag(*sources)                           
+        out = super(*sources)                                        
         if sources.is_a?(Array) and sources[0] == 'jstoolbar/textile'
           out += javascript_tag <<-javascript_tag                    
 jsToolBar.prototype.elements.termlink = {                            
@@ -17,7 +17,9 @@ javascript_tag                                      
         end                                                          
         out                                                          
       end                                                            
-     alias_method_chain :javascript_include_tag, :glossary           
+    end                                                              
+    module AssetTagHelper                                            
+      prepend AssetTagHelperIncludeTag                               
     end                                                              
   end                                                                
 end                                  

高橋 徹 さんが6年以上前に更新

先の当てずっぽう修正後、rake redmine:plugins:migrate すると次のエラー

Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:

  class CreateTerms < ActiveRecord::Migration[4.2]
vendor/bundler/ruby/2.4.0/gems/activerecord-5.1.6/lib/active_record/migration.rb:525:in `inherited'
plugins/redmine_glossary/db/migrate/001_create_terms.rb:1:in `<top (required)>'

これは難題だ・・・

Redmine 4.0開発版(trunk)で、新規プラグインを作成し、モデルを生成し、そのmigrateの雛形を確認すると

class CreateTerms < ActiveRecord::Migration[5.1]
  def change
    create_table :terms do |t|
    end
  end
end

となっていた。どうやら、RailsのバージョンがMigrationの後ろに付く模様。そこで、db/migrate/の下にあるマイグレーションコードの継承クラス名を、ActiveRecord::MigrationからActiveRecord::Migration[5.1]に修正。

diff --git a/db/migrate/001_create_terms.rb b/db/migrate/001_create_terms.rb
index c8cb3b9..3974adc 100644
--- a/db/migrate/001_create_terms.rb
+++ b/db/migrate/001_create_terms.rb
@@ -1,4 +1,4 @@
-class CreateTerms < ActiveRecord::Migration
+class CreateTerms < ActiveRecord::Migration[5.1]
   def self.up
     # CreateTermCategories
     create_table :term_categories, :force => true do |t|
diff --git a/db/migrate/002_create_glossary_styles.rb b/db/migrate/002_create_glossary_styles.rb
index 512477c..4e9e55f 100644
--- a/db/migrate/002_create_glossary_styles.rb
+++ b/db/migrate/002_create_glossary_styles.rb
@@ -1,4 +1,4 @@
-class CreateGlossaryStyles < ActiveRecord::Migration
+class CreateGlossaryStyles < ActiveRecord::Migration[5.1]
   def self.up
     create_table :glossary_styles do |t|
       t.column :show_desc, :boolean, :default => false
diff --git a/db/migrate/003_terms_add_columns.rb b/db/migrate/003_terms_add_columns.rb
index af949fe..cc3d873 100644
--- a/db/migrate/003_terms_add_columns.rb
+++ b/db/migrate/003_terms_add_columns.rb
@@ -1,4 +1,4 @@
-class TermsAddColumns < ActiveRecord::Migration
+class TermsAddColumns < ActiveRecord::Migration[5.1]
   def self.up
     add_column :terms, :tech_en, :string, :default => ''

プラグインのマイグレーションを実行すると、エラーは解消、ただしDEPRECATION WARNINGが出ている。

DEPRECATION WARNING: Using a dynamic :action segment in a route is deprecated and will be removed in Rails 5.2. (called from instance_eval at trunk/config/routes.rb:377)

おそらく、routes.rbの次の記述(URLパスの中に:actionが含まれる)が警告対象

    match 'projects/:project_id/glossary/:action', :controller => :glossary, :via => :all

高橋 徹 さんが6年以上前に更新

一応マイグレーションは終わったので(alias_method_chainの書き換えは仮のまま)、実行したところプロジェクトメニューの[用語集]をクリックすると次のエラーが発生した。

undefined method `before_filter' for GlossaryController:Class
  :
plugins/redmine_glossary/app/controllers/glossary_controller.rb:7:in `<class:GlossaryController>'
plugins/redmine_glossary/app/controllers/glossary_controller.rb:2:in `<top (required)>'

該当コードは次

class GlossaryController < ApplicationController
  menu_item :glossary
  unloadable

  layout 'base'
  before_filter :find_project, :authorize
  before_filter :find_term, :only => [:show, :edit, :destroy]
  before_filter :retrieve_glossary_style, :only => [:index, :show, :show_all, :import_csv_exec]

before_filterは、Rails 5ではbefore_actionに単純に書き換えればよいようです。

--- a/app/controllers/glossary_controller.rb
+++ b/app/controllers/glossary_controller.rb
@@ -4,9 +4,9 @@ class GlossaryController < ApplicationController
   unloadable

   layout 'base'
-  before_filter :find_project, :authorize
-  before_filter :find_term, :only => [:show, :edit, :destroy]
-  before_filter :retrieve_glossary_style, :only => [:index, :show, :show_all, :import_csv_exec]
+  before_action :find_project, :authorize
+  before_action :find_term, :only => [:show, :edit, :destroy]
+  before_action :retrieve_glossary_style, :only => [:index, :show, :show_all, :import_csv_exec]

   helper :attachments
   include AttachmentsHelper

高橋 徹 さんが6年以上前に更新

[管理]>[プラグイン]で、glossary pluginの右端の[設定]をクリックすると次のエラー

undefined method `attr_accessible' for #<Class:0x00007fffc16dea70>

  attr_accessible :project_id, :category_id, :author, :name, :name_en, :datatype, :codename, :description,
                  :rubi, :abbr_whole

高橋 徹 さんが6年以上前に更新

#81-5 の修正をしてサーバーを再起動(再起動しないと、LoadError
Unable to autoload constant GlossaryController というエラーが出る)すると、プロジェクトメニューの[用語集]をクリックすると別なエラーが発生した。

NoMethodError in GlossaryController#index
undefined method `attr_accessible' for #<Class:0x00007fffdb947f18>

  belongs_to :project

  attr_accessible :groupby

  def grouping?
    case groupby

#81-6 と同じくattr_accessibleがエラーとなった。対処方法をググってみると、「ストロングパラメータ」なるものを使う模様。まずモデルからattr_accessible行を削除、コントローラーにストロングパラメータの記述(privateなメソッドでモデル名_paramsを定義、params.require(モデル名).permit(属性名) を呼ぶ)をするようです。

まず、GlossaryStyleモデルからattr_accessibleを削除

--- a/app/models/glossary_style.rb
+++ b/app/models/glossary_style.rb
@@ -11,8 +11,6 @@ class GlossaryStyle < ActiveRecord::Base

   belongs_to :project

-  attr_accessible :groupby
-
   def grouping?

GlossaryStylesControllerコントローラーにストロングパラメータの設定を追加

--- a/app/controllers/glossary_styles_controller.rb
+++ b/app/controllers/glossary_styles_controller.rb
@@ -58,4 +58,10 @@ class GlossaryStylesController < ApplicationController
     add_search_params(newparams)
     redirect_to(newparams)
   end
+
+  private
+
+    def glossary_style_params
+      params.require(:glossary_style).permit(:groupby)
+    end
 end

ここで、誰がglossary_style_paramsを呼ぶのかが不明。要調査。
⇒ コントローラーにcreateメソッドを定義し、その中でストロングパラメータのメソッドを呼ぶ模様。

def create
  GlossaryStyle.create(glossary_style_params)
end

ということなのかな?よく分からず。

もう一つTermモデルとGlossaryControllerコントローラーにも同じくattr_accessibleの修正をした。

--- a/app/models/term.rb
+++ b/app/models/term.rb
@@ -19,8 +19,6 @@ class Term < ActiveRecord::Base
                   :type => 'terms',
                   :url => Proc.new {|o| {:controller => 'glossary', :action => 'show', :id => o.project, :term_id => o.id} }

-  attr_accessible :project_id, :category_id, :author, :name, :name_en, :datatype, :codename, :description,
-                  :rubi, :abbr_whole

--- a/app/controllers/glossary_controller.rb
+++ b/app/controllers/glossary_controller.rb
@@ -177,6 +177,10 @@ class GlossaryController < ApplicationController

   private

+  def term_params
+    params.require(:term).permit(:project_id, :category_id, :author, :name, :name_en, :datatype, :codename, :descriptio
n, :rubi, :abbr_whole)
+  end
+

ちゃんとした修正方法を見出す必要がある。

高橋 徹 さんが約6年前に更新

  • ステータス新規 から 進行中 に変更
  • 進捗率0 から 50 に変更

高橋 徹 さんが約6年前に更新

#81-3 の内容について追加情報

alias_method_chainでやろうとしていることは、wikiツールバーを表示するJavaScriptを読み込むタイミングをインターセプトして用語リンクのマクロを挿入するボタンを追加すること。
JavaScriptの読み込みタイミングは、javascript_include_tagメソッドを引っ掛け、その引数(JavaScriptファイルのパス)がjstoolbar/textileである、すなわちRedmineのpublic/javascripts/jstoolbar/textile.js を読み込むときとしている。

javascript_include_tagメソッドは、ファイルapp/helpers/application_helper.rbの中でModule ApplicationHelperの特異メソッドとして定義されている。
また、Redmine 4.0のコード内でjavascript_include_tagを呼び出す箇所を見て回ったところ、textile.jsを指定しているコードは見つからず、近そうな次のJavaScriptファイルを指定している箇所が見つかった。

  • jstoolbar/jstoolbar-textile.min
  • jstoolbar/lang/jstoolbar_<言語コード>.js

http://www.redmine.org/projects/redmine/repository/revisions/10095

修正はここで入っている。修正前は、jstoolbar/textileを指定していたが、修正後はjstoolbar/jstoolbar-textile.minを指定している。
コメントを見ると、jstoolbar.jsとtextile.jsをマージして整理したものがjstoolbar-textile.min.jsとのこと。

よって、手の入れ方を変える必要がありそうだ。

高橋 徹 さんが約6年前に更新

alias_method_chain を prepend に置き換える

Wiki編集エリアに表示するツールバーは、JavaScriptで記述され、<Redmine基点>/public/javascripts/jstoolbar/ディレクトリ下にファイルが置かれています。このJavaScriptファイルを読み込むタイミングに割り込み、用語マクロを展開するボタンを1つ追加する処理を入れるものです。

JavaScriptを読み込むメソッドはjavascript_include_tagですが、定義場所を調べると2つあり、Ruby on RailsのActionViewの中と、Redmineのapplication_helperの中となります。Redmineの定義はRuby on Railsのそれをオーバーライドして追加処理(プラグインディレクトリのassets下にあるJavaScriptを読む)を入れたものです。

Glossaryプラグインのオリジナルの処理(alias_method_chain)は、Ruby on Rails側のjavascript_include_tagメソッドの処理をフックしていますが、今後を考えるとRedmineのjavascript_include_tagメソッドに対してprependするのがよいと思うのでそのように修正をしていきます。

Redmine本体のjavascript_include_tagメソッドは、app/helpers/application_helper.rb の中でmodule ApplicationHelperに定義されています。
Ruby on Railsのjavascript_include_tagメソッドは、gemのactionview内に、lib/action_view/helpers/asset_tag_helper.rb の中でmodule ActionView::Helpers::AssetTagHelperに定義されています。

  • ファイル名の変更
    パッチ先の場所がactionview(モジュールActionView::Helpers::AssetTagHelper)からredmine(モジュールApplicationHelper)に変わるので、ファイル名もglossary_asset_tag_helper_patch.rbからglossary_application_helper_patch.rbに変更します。
  • prependするモジュール名は、prepend先のモジュール名ApplicationHelperの接頭辞にGlossaryを付けたGlossaryApplicationHelperとします。
    module GlossaryApplicationHelper
      def javascript_include_tag(*sources)
        out = super(*sources)
        if sources.is_a?(Array) and sources[0] == 'jstoolbar/jstoolbar-textile.min'
          out += javascript_tag <<-javascript_tag
    jsToolBar.prototype.elements.termlink = {
        type: 'button',
        title: '#{l(:label_tag_termlink)}',
        fn: {
          wiki: function() { this.encloseSelection("{{term(", ")}}") }
        }
    }
    javascript_tag
          out += stylesheet_link_tag 'termlink', :plugin => 'redmine_glossary'
        end
        out
      end
    end
    
    ApplicationHelper.prepend GlossaryApplicationHelper
    
  • ファイル名を変更したので、init.rbのrequire文を修正します。
    -require 'glossary_asset_tag_helper_patch'
    +require 'glossary_application_helper_patch'
    

Glossaryプラグインを使用しないプロジェクトのWiki編集に用語リンクボタンが表示されるのも今一なので、表示条件をGlossaryプラグインを使用するプロジェクトのWiki編集時に変更します。

   def javascript_include_tag(*sources)
     out = super(*sources)
-    if sources.is_a?(Array) and sources[0] == 'jstoolbar/jstoolbar-textile.min'
+    if @project.try!(:module_enabled?, 'glossary') and sources.is_a?(Array) and sources[0] == 'jstoolbar/jstoolbar-textile.min'
       out += javascript_tag <<-javascript_tag

高橋 徹 さんが約6年前に更新

redmine:plugins:migrateタスクを実行するとエラー(プラグインによらず、プラグインがなくても)

Migrating redmine_glossary (Redmine Glossary Plugin)...
rails aborted!
NoMethodError: undefined method `migrate' for Redmine::Plugin::Migrator:Class
/work/redmine/lib/redmine/plugin.rb:482:in `migrate_plugin'
/work/redmine/lib/redmine/plugin.rb:454:in `migrate'
/work/redmine/lib/redmine/plugin.rb:468:in `block in migrate'
/work/redmine/lib/redmine/plugin.rb:467:in `each'
/work/redmine/lib/redmine/plugin.rb:467:in `migrate'
/work/redmine/lib/tasks/redmine.rake:135:in `block (3 levels) in <top (required)>'
  :

ActiveRecord::Migrator::migrate(a, b) を呼ぼうとしているが、Rails 5.1まであったがRails 5.2で削除されている。

Redmineのチケットに登録あり
https://www.redmine.org/issues/28934

パッチとテストコードが添付されているので、近々マージされると思われます。

高橋 徹 さんが約6年前に更新

GlossaryControllerのnewメソッドがどのタイミングで呼ばれどのようにふるまうのかが謎。

Ruby on Railsの教科書的な作りでは、
  • HTTP Client から new リクエスト(GET)でコントローラーのnewメソッド起動
    • コントローラーのnewメソッド内で空のモデルをnew
    • new.html.erb テンプレートからフォームを含むHTMLをHTTP Clientに返却
  • HTTP Client からモデルリソースへ設定する内容を含むフォームをサブミット (POST)
    • サブミットによりコントローラーのcreateメソッド起動
    • フォームのパラメーターをモデルにセットしモデルを永続化(save)
    • モデルの詳細表示(showアクション)へリダイレクト
    • コントローラーのshowメソッド起動
    • show.html.erb テンプレートから新たに作成されたモデルの詳細表示HTMLをHTTP Clientに返却
一方、Glossaryプラグインの作りは
  • HTTP Client から new リクエスト(GET)でコントローラーのnewメソッド起動
  • コントローラーの中でリクエストが GETまたはXHR(AJAX)か判別
    • 偽であれば
      • モデルを永続化(save)
      • 続けて作成であれば 再びコントローラーのnewへリダイレクト(GET)
      • おしまいであればコントローラーのshowへリダイレクト(GET)
    • 真であれば
      • new.html.erb テンプレートからフォームを含むHTMLをHTTP Clientに返却

というちょっと複雑(ダブルミーニング)なメソッドとなっています。

GlossaryStylesControllerも変則的なアクションになっていて
  • search アクションはGETで呼ばれる
  • edit アクションはPOSTで呼ばれる

Railsのルーティング設定で、リソース定義を使うとeditアクションはGETとなります。
用語集プラグインのコントローラーの作り方をRailsの標準形式に変えたいところですが、それはRedmine 4.0移植が済んだ後のリファクタリングで実施することとします。

高橋 徹 さんが約6年前に更新

リンクエラー

unable to convert unpermitted parameters to hash

発生個所は次
  • app/views/glossary/index.html.erb
    <%= f.link_to 'CSV', :url => params %>
    

paramsの内容は次

{"controller"=>"glossary", "action"=>"index", "project_id"=>"glossarytest"}

エラーメッセージでぐぐると、Rails 5から、パラメーターがハッシュ継承ではなくなったとあります。また、permissionがtrueでないと次のパスに渡せないとありました。

https://qiita.com/DialBird/items/28324de658773b0b34a0

そこで、ハッシュ化しpermissionを与えるコードを明示的に記述します。

-    <%= f.link_to 'CSV', :url => params %>             
+    <%= f.link_to 'CSV', :url => params.permit!.to_h %>

高橋 徹 さんが約6年前に更新

ストロングパラメーターの実装に関して、HTTPリクエストパラメーターを受け取ってカテゴリモデルTermCategoryを生成するのは、教科書的にはTermCategoriesControllerであるが、本プラグインの実装では、GlossaryControllerのadd_term_categoryメソッドで生成している。

GlossaryControllerは肥大化しているので、いずれadd_term_categoryをTermCategoriesControllerに移動させる(対応するビューも)が、今回はTermCategoryを生成するストロングパラメーターの実装をGlossaryControllerにも記述する。

さて、GlossaryControllerのadd_term_categoryであるが、これもHTTPのGETメソッドとPOSTメソッドで起動され、それぞれで異なるふるまいをするダブルミーニングな実装となっている。

TermCategoriesControllerのeditメソッドもHTTPのGETとPATCHのダブルミーニングとなっている。

高橋 徹 さんが約6年前に更新

削除のルーティング設定について

もとのroutes.rbには、次のように削除のルーティング設定が記載されている。

match 'projects/:project_id/glossary/destroy', :to => 'glossary#destroy', :via => [ :delete ]

これを、matchを使わないよう書き換えたが

delete '/projects/:project_id/glossary/:id/destroy', to: 'glossary#destroy'

実行すると次のエラーとなった。
No route matches [POST] "/projects/glossarytest/term_categories/destroy"

削除のリンクが、HTTPのDELETEメソッドではなくPOSTメソッドで出ている模様。

元のルーティング設定をよくよく見ると

match 'projects/:project_id/glossary/:action', :controller => :glossary, :via => :all

というワイルドカードルーティング設定が存在している。おそらく、こちらが効いていたのかと思われる。削除リンクの定義箇所を調べてみると、

  • app/views/glossary/_index_in_category.html.erb
    <%= link_to_if_authorized(image_tag('delete.png'), {:action => 'destroy', :project_id => @project, :id \=> term}, :confirm => l(:text_are_you_sure), :method => :post, :title => l(:button_delete)) %>
    

とHTTPメソッドがPOSTと指定されている。

ここは、Redmine 4.0対応上は現行踏襲を優先とするが後日書き換えることとする。

高橋 徹 さんが約6年前に更新

テストについても考慮していく必要がある。
まず、現状でテストを実行してみるとどうなるか確認

$ bundle exec rails redmine:plugins:test NAME=redmine_glossary RAILS_ENV=test

rails aborted!
LoadError: cannot load such file -- /work/test/test_helper
:

次のブログに同じ問題と解決策が掲載されていた。
http://d.hatena.ne.jp/kk_Ataka/20140224/1393251209

Redmine 1.x までは、vendor/plugin/下にプラグインディレクトリがあったが、Redmine 2.0からはplugin/下にプラグインディレクトリがあります。

-require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')

階層が変わったので、その修正を入れます。

高橋 徹 さんが約6年前に更新

Redmine 4以降で動作するプラグインを作る場合、init.rbのrequires_redmineにバージョンを指定することになるが、trunkのredmineは3.4.6のままなので、テスト時にredmineのバージョンを4.0.0に修正したい。

バージョンを定義するファイルを探したところ

  • lib/redmine/version.rb にあり
    module Redmine
      # @private
      module VERSION
        MAJOR = 3
        MINOR = 4
        TINY  = 6
    
        # Branch values:
        # * official release: nil
        # * stable branch:    stable
        # * trunk:            devel
        BRANCH = 'devel'
    

高橋 徹 さんが約6年前に更新

  • カテゴリRedmine にセット

テスト実行時に次の警告メッセージが表示されます。

$ bundle exec rails redmine:plugins:test:units RAILS_ENV=test
DEPRECATION WARNING: Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
boolean values and must have old data converted to 1 and 0 (its native boolean
serialization) before setting this flag to true. Conversion can be accomplished
by setting up a rake task which runs

  ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
  ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)

for all models and all boolean columns, after which the flag must be set to
true by adding the following to your application.rb file:

  Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
 (called from <top (required)> at /work/redmine/config/environment.rb:14)

Rails 5.2で入った次の修正によるものです。
https://github.com/rails/rails/pull/29699

用語集プラグインでは、テーブルglossary_stylesでboolean型を使用しています。

高橋 徹 さんが約6年前に更新

  • 関連している 機能 #83: Redmine Glossaryプラグインをリファクタリングする を追加

高橋 徹 さんが約6年前に更新

ユニットテスト(Model)を実施して問題発見

  • app/models/term_category.rb
    Term.update_all("category_id = #{reassign_to.id}", "category_id = #{id}")
    

このコードが次のエラーとなる。

ArgumentError: wrong number of arguments (given 2, expected 1)

Rails 5.2のドキュメントによると、

Method: ActiveRecord::Relation#update_all
#update_all(updates) ⇒ Object
引数updatesは、文字列、配列、ハッシュのいずれかで、SQL文の部分集合を表す

とあるので、2つの引数を指定するのは(ハッシュのブラケット省略出ない限り)エラー。

高橋 徹 さんが約6年前に更新

用語のユニットテスト実施メモ

Termクラスではvalidationを次のように指定している。

validates_presence_of :name, :project

TermTestクラスでfixturesの指定は最初次のようにしていた。

plugin_fixtures :terms

terms.ymlには、project_idで値を指定していたが、validationチェック(valid?メソッド)ではprojectがナイトのエラーとなっていた。どうやら、project_idに何か値が入っているだけではだめで、project_idからprojectインスタンスが生成できないとならないらしい。

そこで、fixturesの指定にprojectを追加したところ、テストが進んだ。

  fixtures :projects
  plugin_fixtures :terms

高橋 徹 さんが約6年前に更新

用語のユニットテスト実施メモ

Termのカラムには、created_onとupdated_onがある。
用語を新規作成すると、作成時点での日時が両方のカラムに入る。
用語を編集すると、編集時点の日時がupdated_onに入る。

よって、terms.ymlの有効な定義とするには、created_onとupdated_onの双方に日時の指定要。

高橋 徹 さんが約6年前に更新

コントローラーのテスト(ActiveController::TestCase継承で)

まず、一番単純なモデルであるカテゴリのコントローラーのテストを行う。

indexアクションのテストが実行できるまでの流れをはてな日記に記載。
http://d.hatena.ne.jp/torutk/20180721/p1

高橋 徹 さんが約6年前に更新

用意されているテスト・フィクスチャの内容確認

  • term_categories.yml
id name project_id position
1 one 1 1
2 two 1 1
  • terms.yml
id name project_id category_id
1 term one 1 NULL
2 term two 2 2
  • glossary_styles.yml
id show_desc groupby project_scope
1 NULL NULL 1
2 NULL 1 1

高橋 徹 さんが約6年前に更新

glossary_styles_controller#edit のロジックが複雑な件について

anonymous params[:clear]指定あり session[:glossary_style] = nil
params[:clear]指定なし session[:glossasy_style] = params[:glossary_style]

glossary_styles_controller#edit で次の記述があるが

      unless params[:glossary_style_id].blank?
        @glossary_style = GlossaryStyle.find_by(:user_id => User.current.id)
      end

params[:glossary_style_id]が存在するとき、ユーザーIDで検索するので判定ロジックが逆ではなかろうか?

editアクションを呼び出すビューは、app/views/glossary_styles/_form.html.erb にあり。

フォームのパラメータは

キー名 入力種類 取りうる値
show_desc チェックボックス 0, 1
project_scope 選択リスト 0(ProjectCurrent), 1(ProjectMine), 2(ProjectAll)
groupby ラジオボタン 0(GroupByNone), 1(GroupByCategory), 2(GroupByProject)
clear サブミット(クリア) 'clear' ?

HTTPリクエストのパラメータ例

<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"FVBvc5KZVDQ66yQ4v75+gz3FopWzqM/QRrsSAkVmLRwgdZajlHyoz6SlR0pQXbZsHiMPMUi9iyp/bcOfuihQKg==", "glossary_style"=>{"show_desc"=>"0", "project_scope"=>"0", "groupby"=>"1", "sort_item_0"=>"", "sort_item_1"=>""}, "commit"=>"表示", "project_id"=>"glossary-test", "controller"=>"glossary_styles", "action"=>"edit"} permitted: false>

高橋 徹 さんが約6年前に更新

glossary_controller のテストで nilに対するempty?呼び出しで例外発生

  • fixtures/terms.yml
      name_en: 
      codename: 
    

このfixtureの記述は、データベース上値がNULLとなる。
スキーマ上、termsテーブルのname_enカラムとcodenameカラムは、NOT NULL制約はないが、DEFAULT ''となっている。コントローラーのコードは、レコードの値がNULLを考慮していない。どうしたものかと考え、fixturesにデフォルト値を記載することとした。なお、datatypeがfixtureにないので合わせて追加

-  name_en:
-  codename:
+  name_en: ''
+  codename: ''
+  datatype: ''

高橋 徹 さんがほぼ5年前に更新

  • 関連している 機能 #95: Redmine 4.xに対応するRedmine Glossaryプラグインを、旧バージョンのデータベースを引き継ぎ、且つコードをきれいに再構築する を追加

他の形式にエクスポート: Atom PDF