当社のサービス紹介やブログ等をお読みの方の多くはRedmineに興味を持たれ、ご利用・ご検討いただいていると思います。 Redmineの改善作業を行っていますと実際に入力した情報(データ)をどのように取り扱っているのか非常に興味を惹かれます。 今回は少し異質(特徴的)なデータの持ち方をしている UserPreference についてご紹介します。
sqlite> .header on sqlite> .mode column sqlite> pragma table_info('user_preferences'); cid name type notnull dflt_value pk ---------- ---------- ---------- ---------- ---------- ---------- 0 id integer 1 1 1 user_id integer 1 0 0 2 others text 0 NULL 0 3 hide_mail boolean 0 1 0 4 time_zone varchar 0 NULL 0
user_preferencesテーブルの構造
UserPreferenceとは、Redmineの中で定義されたモデルのひとつです。そのUserPreferenceが初めて登場したのは2006年12月4日の リビジョン 62 でした。この時はマイページに表示したいブロック(カレンダーや文書等)と配置場所(レイアウト)を利用者(ユーザ)ごとに管理(保持)するために UserPreference が作成されたようです。これ以降利用者(User)ごとのさまざまな(任意の)設定情報を格納しています。
ユーザに関する任意の設定情報は主に UserPreference(実テーブル:user_preferences)の others 列(カラム)で管理しています。この others は ActiveRecord::AttributeMethods::Serialization.serialize を使って宣言します。実際のデータはHashですがこれを YAML形式 に文字列化(シリアライズ)して格納します。Hashなので特定のデータ型に縛られない点が他のモデル(テーブル)とは異なります。
UserPreference#others 宣言部(app/models/user_preference.rb)
class UserPreference < ActiveRecord::Base include Redmine::SafeAttributes belongs_to :user serialize :others
UserPreference の格納データ
$ RAILS_ENV=development bundle exec rails console Loading development environment (Rails 5.2.3) [1] pry(main)> user_preference = User.find(2).pref User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('User', 'AnonymousUser') AND "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]] UserPreference Load (0.1ms) SELECT "user_preferences".* FROM "user_preferences" WHERE "user_preferences"."user_id" = ? LIMIT ? [["user_id", 2], ["LIMIT", 1]] => #"0", :comments_sorting=>"asc", :warn_on_leaving_unsaved=>"1", :textarea_font=>"", :my_page_layout=>{"left"=>["issuesassignedtome"], "right"=>["issuesreportedbyme"], "top"=>["issuesupdatedbyme"]}, :my_page_settings=>{}, :recently_used_project_ids=>"1"}, hide_mail: true, time_zone: ""> [2] pry(main)>
others への値の設定・取得は、othersに直接ではなくアクセサメソッドを介して行っています。アクセサメソッドを使うことで設定可能な属性(キー)を制限することができます。
アクセサメソッドの一部(app/models/user_preference.rb)
def [](attr_name) if has_attribute? attr_name super else others ? others[attr_name] : nil end end def []=(attr_name, value) if has_attribute? attr_name super else h = (read_attribute(:others) || {}).dup h.update(attr_name => value) write_attribute(:others, h) value end end def no_self_notified; (self[:no_self_notified] == true || self[:no_self_notified] == '1'); end
アクセサメソッドの使用例
[2] pry(main)> user_preference.no_self_notified => false [3] pry(main)> user_preference.no_self_notified = '1' => "1" [4] pry(main)> user_preference.no_self_notified => true [5] pry(main)> user_preference => #<UserPreference:0x00007f87acac3b28 id: 2, user_id: 2, others: {:no_self_notified=>"1", :comments_sorting=>"asc", :warn_on_leaving_unsaved=>"1", :textarea_font=>"", :my_page_layout=>{"left"=>["issuesassignedtome"], "right"=>["issuesreportedbyme"], "top"=>["issuesupdatedbyme"]}, :my_page_settings=>{}, :recently_used_project_ids=>"1"}, hide_mail: true, time_zone: ""> [6] pry(main)>
UserPreference はとても便利なモデルです。同様にシリアライズ(文字列化)したデータを格納するモデルは他にもあります(Role, CustomField, Query等)が、さまざまなデータ型を格納し利用しているのは UserPreference だけではないかと思います。UserPreferenceのおかげでRedmineの使い勝手が向上している画面(機能)もあります。
個人的には Redmine.org - Feature #4016: Make app settings overridable at project level で UserPreference と同等の機能を持つ(ProjectPreference のような)モデルが組み込まれればプロジェクトごとの設定項目を拡張することも容易になる (画面テーマなどもプロジェクト単位で設定が可能になる)はずです。これによりRedmineはさらに使い勝手が良くなると思います。
Redmineには特徴的なモデルや機能(処理)が他にもありそうです。今後もRedmine改善作業を行いながら新たな技術や実装方法を見つけ出したいと思います(宝探しをしているような気持ちもありますけど)。
ファーエンドテクノロジーによるRedmine開発状況(2019年1〜4月) ファーエンドテクノロジーによる2019年1月〜4月のRedmineの開発状況です。注目している新機能やイチ押し機能をご紹介! |
|
ShowNetの裏側を見た! InteropのShowNetテクニカルツアー&セッションに参加。NOC内部など裏側にも入り、スタッフの情熱を肌で感じました。 |
|
「Redmine 4.1 新機能選抜総選挙」で紹介できなかった新機能 10選 redmine.tokyoでRedmine4.1の新機能16個を紹介。そのほか紹介できなかった便利な新機能10個をピックアップして紹介します。 |
|
初めて行った韓国で驚いたこと・印象に残ったこと GWに旅行で韓国へ。料理は量が多くて安い、電車賃も安い韓国と日本との違いを楽しみました。 |
|
なんでこの機能Redmineにないの??の裏事情 Redmineで「こんな機能あったらいいのにな」と思う機能があります。どういった理由で作業が止まっているのでしょうか。 |
2024年9月14日 オライリー本の全冊公開日のお知らせ(もくもく勉強会も同時開催) ファーエンドテクノロジーが所蔵するオライリー本(全冊)公開日のご案内です。公開日には「もくもく勉強会」も同時開催します。 |
|
RubyWorld Conference 2024 (12/5・6開催) にPlatinumスポンサーとして協賛 ファーエンドテクノロジー株式会社は、2024年12月5日(木)〜6日(金)に島根県松江市で開催される「RubyWorld Conference 2024」にPlatinumスポンサーとして協賛しています。 |
|
プロジェクト管理ツールRedmineのクラウドサービス「My Redmine」の海外向けサービス「My Redmine Global Edition」の提供を開始 「My Redmine」の海外向けサービスとして、新たに「My Redmine Global Edition」の提供を開始しました。 |
|
Redmineの最新情報をメールでお知らせする「Redmine News」配信中 新バージョンやセキュリティ修正のリリース情報、そのほか最新情報を迅速にお届け |