【Rails】rails-adminを使って簡単に管理画面を作る
簡単に管理画面をつくりたい
ユーザー情報を一覧で見られる単純な管理画面があればいいので、一番簡単に管理画面ができそうなrails-admin
を使いました。
rails-admin
× sorcery
の参考記事が見つからなかったのでブログに残しておきます。
環境
Rails 6.0.3
ruby 2.7.2
認証はgem 'sorcery'
を使用しています。
User
モデルがあり、role
カラムで管理者と一般ユーザーを分類しています。
実装の流れ
gem 'rails-admin'
のインストール- 認証用
sorcery
の設定 - 認可用
gem 'cancancan'
のインストール
rails-adminのインストール
Gemfileに追記
gem 'rails_admin', '~> 2.0'
Run bundle install
ターミナルで実行
rails g rails_admin:install
名前空間を聞かれるので、
/admin
でよければ、Enter
キーを押すサーバを再起動してから、
/admin
にアクセスする。
これでもう既に形はできている。簡単。
翻訳ファイル
Japanese translation for RailsAdmin · GitHub
これをコピペしてconfig/locales/views/rails_admin_ja.yml
に貼り付け。
認証機能を追加
今はログインしていなくても誰でも管理画面にアクセスできる状態なので、認証機能を追加していきます。
認証はsorcery
を使用しているので、公式のwikiのsorcery設定のページを参考にします。
Sorcery · sferik/rails_admin Wiki · GitHub
(略) RailsAdmin.config do |config| config.authenticate_with do #sorceryのメソッド require_login end config.current_user_method(&:current_user) config.parent_controller = 'ApplicationController' #追記 end (略)
class ApplicationController < ActionController::Base before_action :require_login private def not_authenticated flash[:info] = 'ログインしてください' redirect_to main_app.login_path #main_appのプレフィックスをつける end end
最初、main_app
の意味がわからなかったので、省略していたら、No route matches~
のエラーが出てしまいました。
調べてみると、アプリケーションのルーティングと明記する必要があった。
ルーティングプロキシメソッド呼び出しを省略したアプリケーション側のルーティングヘルパーメソッドを、エンジン内でレンダリングされるテンプレートから呼び出そうとすると、未定義メソッド呼び出しエラーが発生することがあります。
このような問題が発生した場合は、アプリケーション側のルーティングメソッドをエンジンから呼びだすときに、main_app
というプレフィックスを付け忘れていないかどうかを確認してください。
認可機能の追加
管理者以外は、アクセスできないようにします。
gem 'cancancan'
を使います。
rails-admin
の公式がこちらを勧めている&ここ以外で使う予定がないので素直に従います。
gem 'cancancan'
追記してbundle install
rails g cancan:ability
公式に設定方法があるのでそのとおりに実装していきます。Lintは多少修正。 Authorization · sferik/rails_admin Wiki · GitHub
CanCanCan · sferik/rails_admin Wiki · GitHub
class Ability include CanCan::Ability def initialize(user) return unless user && user&.admin? # 管理者じゃなかったらこのメソッドを抜ける can :access, :rails_admin # 管理者画面のアクセス許可 can :manage, :all # 管理権限許可 end end
更に、先程のrails_admin
側の設定ファイルに追記する。
RailsAdmin.config do |config| config.authenticate_with do require_login redirect_to root_path unless current_user.admin? # 追記 end config.current_user_method(&:current_user) ## == CancanCan == config.authorize_with :cancancan # コメントアウトを外す (略) end config.parent_controller = 'ApplicationController' end
完成
【エラー解消メモ】[BUG] Segmentation fault
エラー
ローカルではRSpecが通るのに、CircleCI上で落ちてしまう。
環境
Rails 6.0.3
Dockerのimageは以下のとおり
jobs: build: docker: - image: circleci/ruby:2.7.2-node-browsers-legacy
エラー内容
今まで遭遇したことのないSegmentation fault
エラー文をダウンロードして見てみる。
..*..................../home/circleci/repo/vendor/bundle/ruby/2.7.0/gems/sassc-2.4.0/lib/sassc/engine.rb:43: [BUG] Segmentation fault at 0x0000000000000000 ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux]
sassc
が問題のよう。
公式のissue
を見てみると、同じエラーの人がいて、解決方法も載っていました。
segfault on 2.3.0 · Issue #197 · sass/sassc-ruby · GitHub
Same here
at sassc-2.3.0/lib/sassc/engine.rb:43: [BUG] Segmentation fault at 0x0000000000000000 ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
解決方法
以下を追加
Rails.application.config.assets.configure do |env| env.export_concurrent = false end
やっと通った
原因
sprocketsとwebpackerのコンパイルが並行して行われているため、問題が起こる…らしいので、先の解決方法のコードで並行処理をしないように設定する。
正直、よくわからない
chartkick × Highchartsでドーナツグラフを作る
実装したいこと
- ドーナツグラフの真ん中に合計額
- ラベルはグラフ上に表示
- ラベルが細かくて重なってしまう場合は非表示
- 凡例を非表示
chartkick
を使用したら、簡単に実装できました。
ただ、chartkick × Highcharts
についての日本語記事がほぼない&各オプションの指定が公式から探しにくく、苦労しました。
chartkick
では、chart-js
Google Charts
Highcharts
を使用することができます。
最初、chart-js
を使用していたのですが、細かい設定はできない&ラベル表示がデフォルトでないため扱いが難しかったので、途中でHighcharts
に変更しました。見た目もHighcharts
のほうが綺麗な気がします。
環境
rails (6.0.3.4)
"chartkick": "^3.2.1",
"highcharts": "^8.2.2",
chartkickのインストール
GitHub - ankane/chartkick: Create beautiful JavaScript charts with one line of Ruby
gem "chartkick"
Rails6
なので、
yarn add chartkick highcharts
require("chartkick").use(require("highcharts"))
View
line_chart(表示したいデータ)
pie_chart(表示したいデータ)
のように、表示させたいviewファイルに記述するだけでグラフを生成できます。
今回は円グラフを作りたいので、pie_chart
を選択します。
(テンプレートエンジンはslim
を使用)
#公式の例 = pie_chart Goal.group(:name).count
グローバルオプションの追加
今回は1種類のグラフしか使用しないので、全体に適用するグローバルオプションを指定していきます。
Chartkick
で使用できるオプションと、Highcharts
から使うオプションで記述方法が異なります。
Highcharts
のオプションは、library
以下に記述していきます。
Chartkick.options = { donut: true, # ドーナツグラフ width: '400px', colors: [ "#769fcd", "#b9d7ea", "#d6e6f2", "#f7fbfc", ], message: {empty: "データがありません"}, thousands: ",", suffix: "円", legend: false, # 凡例非表示 library: { # ここからHighchartsのオプション title: { # タイトル表示(ここでは、グラフの真ん中に配置して,viewでデータを渡しています。*後述) align: 'center', verticalAlign: 'middle', }, chart: { backgroundColor: 'none', plotBorderWidth: 0, plotShadow: false }, plotOptions: { pie: { dataLabels: { enabled: true, distance: -40, # ラベルの位置調節 allowOverlap: false, # ラベルが重なったとき、非表示にする style: { #ラベルフォントの設定 color: '#555', textAlign: 'center', textOutline: 0, #デフォルトではラベルが白枠で囲まれていてダサいので消す } }, size: '110%', innerSize: '60%', # ドーナツグラフの中の円の大きさ borderWidth: 0, } }, } }
Highchartsの公式でDemoが見られるので、これをcodepenで操作しながらオプションを試しました。 annotations.labelOptions.shadow | Highcharts JS API Reference
View
これは力技で無理やり実装したので、多分もっといい方法がありそう
コントローラーで定義したインスタンス変数@expenses
@sum_of_expenditure
を取得して表示しています。(内容は省略)
= pie_chart @expenses,library: {title: {text: "支出<br> #{@sum_of_expenditure)"}}
グラフ内に表示したいタイトルはグローバルオプションではなく、ローカルオプションで渡します。
【Rails】 default値の変更
ちょっと詰まったのでメモ
フォーム入力画面でplaceholder
を表示させたいけど、デフォルト値を設定していたため、表示できない
良し悪しは置いといて、default値
を削除したい。
DBはMySQL Rails 6.0.3.4
試したけど、できなかったmigrationスクリプト
class ChangeUserProfileColumn < ActiveRecord::Migration[6.0] def up change_column :user_profiles, :age, :integer change_column :user_profiles, :job, :string, limit: 20 end def down change_column :user_profiles, :age, :integer, default: 0 change_column :user_profiles, :job, :string, default: '', limit: 20 end end
class ChangeUserProfileColumnDefault < ActiveRecord::Migration[6.0] def change change_column_default :user_profiles, :age, from: true, to: false change_column_default :user_profiles, :job, from: true, to: false end end
成功したmigrationスクリプト
class ChangeUserProfileColumnDefault < ActiveRecord::Migration[6.0] def change change_column_default :user_profiles, :age, nil change_column_default :user_profiles, :job, nil end end
change_column_default (ActiveRecord::ConnectionAdapters::SchemaStatements) - APIdock
【CircleCI】エラー
モデルスペックは通るのに、システムスペックを追加したら、ローカルではパスするのにCircleCI上で落ちるようになった。 半日苦しんだので、メモ
ローカルでjobを実行できない
❯ circleci local execute --job build Docker image digest: sha256:ed0cf0f38d357f2599fb3872009de30d79664d48b6fb7167c54867befbc0d794 docker: Error response from daemon: dial unix docker.raw.sock: connect: connection refused. See 'docker run --help'.
docker起動してなかった。。。
Systemスペックが落ちる
モデルスペックは問題なし。システムスペックだけ、ローカルでは大丈夫なのにCircleCI上で落ちる。
Error reading historical timing data: file does not exist Requested weighting by historical based timing, but they are not present. Falling back to weighting by name. DEPRECATION WARNING: Initialization autoloaded the constants ActionText::ContentHelper and ActionText::TagHelper. Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails. Reloading does not reboot the application, and therefore code executed during initialization does not run again. So, if you reload ActionText::ContentHelper, for example, the expected changes won't be reflected in that stale Module object. These autoloaded constants have been unloaded. Please, check the "Autoloading and Reloading Constants" guide for solutions. (called from <top (required)> at /home/circleci/repo/config/environment.rb:5) ..........Since there is no EDITOR or BETTER_ERRORS_EDITOR environment variable, using Textmate by default. FFFFFFFF Failures: 1) UserSessions ログイン機能 メールアドレスとパスワードが一致しているとき ログインに成功する Failure/Error: fill_in 'メールアドレス', with: user.email Capybara::ElementNotFound: Unable to find field "メールアドレス" that is not disabled [Screenshot]: /home/circleci/repo/tmp/screenshots/failures_r_spec_example_groups_user_sessions_nested_nested_ログインに成功する_166.png # ./spec/system/user_sessions_spec.rb:10:in `block (4 levels) in <main>'
日本語フォントに対応していない??と思い、フォントをダウンロードしたり色々試したけどできず。
テスト結果のスクリーンショットを見てみる(見方は後述)※色々試すより、先にこの設定をすればよかった。
Webpacker::Manifest::MissingEntryError
ということなので、yarn install
を設定ファイルに追加
steps: - checkout # yarnインストール - run: name: yarn Install command: yarn install
やっとできた!
デバッグ
CircleCIでエラーがでたときのデバッグ方法がわからずに無駄に色々試してしまった
テスト結果を保存する設定を追記する。
これで、CircleCI上のArtifacts
のタブからスクリーンショットを確認できる。
# テスト結果の保存(CircleCI上で見れる) - store_test_results: path: /tmp/test-results destination: test-results - store_artifacts: path: tmp/screenshots destination: test-screenshots
has_oneでbuildメソッドを使うときの書き方
アソシエーションは以下のとおりで、1対1の関係
class User < ApplicationRecord has_one :user_profile, dependent: :destroy end
class UserProfile < ApplicationRecord belongs_to :user end
class UserProfilesController < ApplicationController # 略 def create @user_profile = current_user.user_profile.build(user_profile_params) # 略
こんな感じで、ログインしているユーザー(current_user
)が、プロフィール(UserProfile
)をbuild
…と記述したらエラー。
NoMethodError at /user_profiles undefined method `build' for nil:NilClass Hint: Something is `nil` when it probably shouldn't be.
has_one
で関連付けをしているとき、
build_association
という書き方になる。
@user_profile = current_user.build_user_profile(user_profile_params)
Twitter認証機能の追加
半日以上かかってしまったので、エラー部分について自分用に反省メモφ(・・
127.0.0.1:3000
に飛びたいのに何故か/login
に遷移する
Twitterログインボタンを設置しているTOPページに遷移するためのstatic_pages_controller.rb
でskip_before_action :require_login
してなかった…
CircleCIでエラー
DBをセットアップできていない・・・
rake aborted! NoMethodError: undefined method `[]' for nil:NilClass /home/circleci/repo/config/initializers/sorcery.rb:88:in `block in <main>'
該当箇所をみると、これ
config.twitter.key = Rails.application.credentials.twitter[:key]
CircleCI
側にマスターキーを登録したらOKだった
Rails 6よりサポートされたMulti Environment Credentialsをプロジェクトに導入する
今後の課題
TwitterからEmail取得できない問題
permissionがrejectされる!
とりあえず、email取得は諦めて、usersテーブルのemailカラムにはtwitter_idを詰めてごまかしているので今後対応する