Rails プラグインを学んでみる。(後編)
こんにちは、マリンです。
前回はRailsガイドの「プラグイン作成入門」の3まで書きました。今回は続きの4から書きます。
前回の記事はこちら。
4.“acts_as"メソッドをActive Recordに追加する。
acts_as~
- プラグインのモデルによく追加されるメソッドの名前。
ここでは後に作成する"squawk"メソッドをActive Recordに追加するためのメソッド、"acts_as_yaffle"を追加します。
<必要ファイルの準備>
# test/acts_as_yaffle_test.rb require 'test_helper' class ActsAsYaffleTest < ActiveSupport::TestCase end # lib/yaffle.rb require 'yaffle/core_ext' require 'yaffle/acts_as_yaffle' module Yaffle end # lib/yaffle/acts_as_yaffle.rb module Yaffle module ActsAsYaffle # ここにコードを書く end end # test/acts_as_yaffle_test.rb require 'test_helper' class ActsAsYaffleTest < ActiveSupport::TestCase end # lib/yaffle.rb require 'yaffle/core_ext' require 'yaffle/acts_as_yaffle' module Yaffle end # lib/yaffle/acts_as_yaffle.rb module Yaffle module ActsAsYaffle # ここにコードを書く end end
クラスメソッドを追加する
プラグインはホストアプリにインストールして使うものです。 そのため、もしかするとホストアプリとプラグインでメソッド名が被ってしまうことが起こるかもしれません。その問題を解決するためのクラスメソッドを追加します。
- “yaffle_text_field” : 名前を変更できるようにするメソッド。
<test作成>
# yaffle/test/acts_as_yaffle_test.rb require 'test_helper' class ActsAsYaffleTest < ActiveSupport::TestCase def test_a_hickwalls_yaffle_text_field_should_be_last_squawk assert_equal "last_squawk", Hickwall.yaffle_text_field end def test_a_wickwalls_yaffle_text_field_should_be_last_tweet assert_equal "last_tweet", Wickwall.yaffle_text_field end end
このテストはHickwallとWickwallモデルがないのでRedです。
<モデル作成>
テストを通すために必要なモデルをダミーアプリに作成します。
$ cd test/dummy $ bin/rails generate model Hickwall last_squawk:string $ bin/rails generate model Wickwall last_squawk:string last_tweet:string
マイグレーションを実行して、テストデータベースにテーブルを作成します。
$ cd test/dummy $ bin/rails db:migrate
作成したモデルがyaffles
として振る舞うよう指示します。
# test/dummy/app/models/hickwall.rb class Hickwall < ActiveRecord::Base acts_as_yaffle end # test/dummy/app/models/wickwall.rb class Wickwall < ActiveRecord::Base acts_as_yaffle yaffle_text_field: :last_tweet end
<acts_as_yaffleメソッドを定義>
前述のモデルに使用したacts_as_yaffle
を定義します。
# yaffle/lib/yaffle/acts_as_yaffle.rb module Yaffle module ActsAsYaffle extend ActiveSupport::Concern included do end module ClassMethods def acts_as_yaffle(options = {}) # ここにコードを書く end end end end ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
ここでテストを行うと、今度はyaffle_text_field
が定義されていないということでRedになると思います。前述のモデルに使用したacts_as_yaffle
メソッドを実装し、この中で定義してテストが通るようにします。
# yaffle/lib/yaffle/acts_as_yaffle.rb module Yaffle module ActsAsYaffle extend ActiveSupport::Concern included do end module ClassMethods def acts_as_yaffle(options = {}) cattr_accessor :yaffle_text_field self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s end end end end ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
cattr_accessor
- クラス外から対象のクラス変数へアクセスするためのメソッドです。
- 似たものに
attr_accessor
がありますが、これはインスタンス変数にアクセスするためのメソッドです。
これでテストはGreenになります。
インスタンスメソッドを追加する
先に述べた'squawk'メソッドを追加します。このメソッドはデータベースの値のいずれかひとつを設定するメソッドです。
<テスト作成>
# yaffle/test/acts_as_yaffle_test.rb require 'test_helper' class ActsAsYaffleTest < ActiveSupport::TestCase def test_a_hickwalls_yaffle_text_field_should_be_last_squawk assert_equal "last_squawk", Hickwall.yaffle_text_field end def test_a_wickwalls_yaffle_text_field_should_be_last_tweet assert_equal "last_tweet", Wickwall.yaffle_text_field end def test_hickwalls_squawk_should_populate_last_squawk hickwall = Hickwall.new hickwall.squawk("Hello World") assert_equal "squawk! Hello World", hickwall.last_squawk end def test_wickwalls_squawk_should_populate_last_tweet wickwall = Wickwall.new wickwall.squawk("Hello World") assert_equal "squawk! Hello World", wickwall.last_tweet end end
squawk
が定義されていないのでこれはRedになります。
<'squawk'を定義>
# yaffle/lib/yaffle/acts_as_yaffle.rb module Yaffle module ActsAsYaffle extend ActiveSupport::Concern included do end module ClassMethods def acts_as_yaffle(options = {}) cattr_accessor :yaffle_text_field self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s include Yaffle::ActsAsYaffle::LocalInstanceMethods end end module LocalInstanceMethods def squawk(string) write_attribute(self.class.yaffle_text_field, string.to_squawk) end end end end ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
これでテストはGreenになります。
ここまででプラグインの開発は終了です。
5. ジェネレータ
ジェネレータ
- 与えられた条件などに基づいてデータやプログラムコードを自動的に生成するプログラムなど。
もしgemにジェネレータを含めたい場合には、作成したジェネレータをプラグインのlib/generators
ディレクトリに置くだけで大丈夫です。
6. gemを公開する
せっかく作成したプラグインなので、公開したい場合があると思います。gemはGitリポジトリを使用して共有が可能です。
他のアプリケーションで使用するには、まずgemのコードをリモートリポジトリにコミットし、その後gemを使用したいアプリケーションのGemfileに書いてbundle install
することで利用できます。
gem 'yaffle', git: 'git://github.com/yaffle_watcher/yaffle.git'
この時コードのURLや、ローカルのディレクトリの場合はパスを忘れず書きましょう。
もしgemを正式なリリースとして一般公開するなら、RubyGemsでパブリッシュします。詳細はこちら(英語です。)
ここまでで直接開発に関わる説明は終わりです。
7項は「デプロイするならきちんとドキュメントを書きましょう」という内容なので省略します。
まとめ
基本的にはアプリの開発と同じですね。あとはファイル構成や、gemspec
、本アプリでの使用方法などでつまずかなければいけそうです。
私の場合は自分のサイトにブログ機能を追加することが目的なので、よりホストアプリに寄り添ってるっぽいエンジン(多分似たようなものだと思うのですが)を使って開発していこうと思います。
とはいえ、プラグインが作れるようになるとできることの幅が広がりそうなので、サラッとでも勉強しておくと良さそうですね。
Rails プラグインを学んでみる。(前編)
こんにちは、マリンです。
ポートフォリオサイトのスマホ化がひと段落しましたので、今度はブログ機能をつけようと思います。
せっかくなので、以前ちょこっと触れたプラグインをやってみようと思い、現在RailsガイドさんのRails プラグイン作成入門を勉強しています。
ここまでの内容を勉強ノートとしてまとめ。
PluginとEngine
本文とは少し外れますが、前回触れたのがエンジンで、今勉強中なのがプラグインで・・・
何が違うの?と思ったのでちょっと調べました。
Plugin
Engine
プラグイン同様ホストアプリに機能を提供するものだが、エンジンはよりアプリに近く、ホストアプリのミニチュアのようなもの。
実際にはRailsアプリの方がエンジンを拡張したようなもので、Rails::ApplicationはRails::Engineから多くの振る舞いを継承している。
・・・イマイチなんですが、
どうやらよりホストアプリ寄りなのがエンジンで、いろんなアプリで使ってもらうのを想定しているのがプラグインかな?まぁ、名前的にも。
ということは今回はエンジンのが良さそうですが、
なんとなくプラグインの方が基本ぽかったのでひとまず続けることにしました。
1 設定
gem形式のプラグインを生成する
*ちなみにスケルトンは骨組みです。私はなんか透過的な意味かと思ってました。
$ rails plugin new
このコマンドはあらゆるRails拡張機能の開発用スケルトンを生成するためのものです。
ここで生成したスケルトンには、ダミーのRailsアプリが入っているので、それを使って統合テストなんかも行うことが可能です。
ちなみにこのコマンドで生成されるファイルはこちら。
create create README.md create Rakefile create yaffle.gemspec create MIT-LICENSE create .gitignore create Gemfile create lib/yaffle.rb create lib/tasks/yaffle_tasks.rake create lib/yaffle/version.rb create bin/test create test/test_helper.rb create test/yaffle_test.rb append Rakefile vendor_app test/dummy
2 新しく生成したプラグインをテストする
テストの前に、作成したプラグインのディレクトリでbundle install
します。
が、さらにその前に、.gemspec
ファイルの"TODO"の部分を修正してください。
プラグインではgemの依存関係?などをGemfile
ではなく~.gemspec
ファイルに記述します。
デフォルトのままだとこのファイルに記述できるs.homepage
やらs.summary
やらの内容が"TODO"になっており、このままだとbundle install
した時にエラーになってしまうので、ここを修正してください。
ダミーアプリの中ではrails test
。
3 コアクラスを拡張する
ここではプラグインが使用されるRailsアプリケーションのどこでも利用可能なメソッドを追加する方法を学びます。
追加先 : Stringクラス
追加メソッド : to_squawk
テストファイルの作成
この教材はテスト駆動方式で進めているので、まずテストからです。
core_ext_test.rb
ファイルを作成し、以下のテストを書きます。
require 'test_helper' class CoreExtTest < ActiveSupport::TestCase def test_to_squawk_prepends_the_word_squawk assert_equal "squawk! Hello World", "Hello World".to_squawk end end
まだメソッドが実装されていないのでエラーになります。
メソッドの実装
メソッドを実装してテストが通るようにします。
<require 'yaffle/core_ext'
を追加>
# lib/yaffle.rb require 'yaffle/core_ext' module Yaffle end
プラグインではまずlib
直下のyaffle.rb
(ファイル名はそれぞれです)が呼び出されます。
そのためまずはここで呼び出して欲しいファイル名を記述。
<メソッドの実装>
# lib/yaffle/core_ext.rb String.class_eval do def to_squawk "squawk! #{self}".strip end end
前述のrequire
で呼び出されるファイルにメソッドを定義します。
メソッドを使ってみる
ここまででto_squawk
メソッドが使用できるようになったので、
rails console
で試してみます。
rails console
を実行するには、ダミーアプリに移動してください。
$ cd test $ cd dummy $ bin/rails console >> "Hello World".to_squawk => "squawk! Hello World"
長くなってきたので、今回はここまでにします。
次は「4.“acts_as"メソッドをActive Recordに追加する」から書きます。
サイトをスマホ対応にする
こんにちは、マリンです。
今回作ったサイト、最初からレスポンシブ対応にしていたつもりだったのですが、
いざ本番で動かしてみたらスマホ対応にはなっていなかったようです。
そこで今回、Railsでサイトをスマホ対応にする方法を勉強したので書き綴っておきます。
Action Pack variants
まず、今回はgemは使わずに実装しました。違いがいまいちわからなかったので(笑)
Rails4.1から実装されましたAction Pack Variantsを使用します。
Action Pack Variantsとは、スマホ、タブレット、PCなどのブラウザごとに異なるテンプレートを使用したい場合に、
その振り分けを簡単に実現できるようにするためのRailsの機能です。
手順
Controller
class ApplicationController < ActionController::Base before_action :set_request_variant private def set_request_variant case request.user_agent when /iPad/ request.variant = :phone when /iPhone/ request.variant = :phone when /Android/ request.variant = :phone end end end
application_controller.erb
に上記を記述します。
Private内で振り分けるデバイスを指定します。
メソッド名はなんでも大丈夫ですが、「なんの時にはどのvariant」
ということは明示してあげてください。
後述しますが、私はここで一度失敗しました。
Views
variantごとに個別のテンプレートを用意します。
テンプレートのファイル名には、variantで指定した:~
を記述します。
app/views/index.html.erb #指定外のデバイス app/views/index.html+phone.erb #指定のデバイス
このようにすることで、Railsが自動的にデバイスごとにテンプレートを振り分けて表示してくれます。
失敗編
前述しましたが、指定の仕方が甘くて一度失敗しました。
最初のコード
class ApplicationController < ActionController::Base before_action :set_request_variant private def set_request_variant request.variant = :phone end end
最初はこれしか書いてませんでした。
これだとPCの場合でもスマホのテンプレートが使用されてしまっていました。
そこでこちらの記事を参考にさせていただき、
きちんとcase~when
を使用してそれぞれ指定し、
PCを入れないように記述するとうまくいきました。
まとめ
Bootstrapのレスポンシブ対応=スマホ対応と勘違いしていたことがそもそもの間違いでした。
でもこのVariantの導入でかなり楽にできるようになったようですね。
言語の発展で自動的にやってくれることがたくさんあるため、ついつい忘れてしまいますが、
本来ならコンピュータには1~10まで全て指示しなければいけないんですよね。
どこまでやってくれて、どこから自分でやらなければならないのか、
それもきちんと把握する必要がありそうです。
S3用のIAMを作る
サイトの画像利用のためにAWSのS3を使っています。
そのままマスターのアカウントを使い続けるのはあまり良くないので、
S3用にIAMを使ってユーザーを追加しようと思います。
前提
すでに対象のバケットは作成済み
S3用なのでそれ以外の細かい設定はしません
手順
追加ユーザーの設定
(1)サービスの中からIAMを選択
(2)「ユーザーを追加」を選択
サイドメニューの「ユーザー」を選択して、「ユーザーを追加」をクリックします。
アクセスの種類
プログラムによるアクセス -> アクセスキーやシークレットキーを有効にします。
AWSマネジメントコンソールへのアクセス -> 追加ユーザーがコンソールへアクセスする際のパスワードを有効にします。 (これが無いと一度マスターから入ってパスワードを設定しなければならなくなります)
コンソールのパスワード
- 最初のパスワードの生成方法を自動か手動か選べます。
パスワードのリセットが必要
- 最初にログインした際、任意のパスワードに変更させるかさせないかの設定です。
S3用のポリシーの作成
ポリシーとは所定の書式に従い、1つ以上のアクセス許可を記述したドキュメントのことです。
(1)ポリシーの作成を選択
IAMを前項まで設定し、次に進むと以下のような画面に切り替わります。
ここで「既存のポリシーを直接アタッチ」を選択し、
ポリシー一覧の左上にある「ポリシーを作成」をクリックします。
(2)Policy Ganarator選択
「ポリシーの作成」画面の真ん中の項、「Policy Ganarator」を選択します。
(3)アクセス許可の編集
この編集を3パターン行います。
効果 -> 許可
アクション -> 全てのアクション
ARN -> arm:aws:s3:::バケット名
効果、AWSサービス、アクションまで 1 と同じ。
ARN -> arm:aws:s3:::バケット/*
効果 -> 許可
アクション -> ListAllMyBucktes
ARN -> arm:aws:s3:::*
JSONファイルで色々設定もできるようです。
確認してOKなら右下の「ポリシーを作成」をクリック。
これでS3用のポリシー作成完了です。
こちらのサイトを参考にさせていただきました。
Amazon S3 専用のアカウントを作ってみよう (フェンリル | デベロッパーズブログ)
引き続きユーザーの設定
(1)作成したポリシーを選択
先ほどのポリシー一覧を下にスクロールしていくと作成したポリシーが出てきます。
これをチェック!
(2)確認
「次のステップ:確認」で確認画面が出ます。
OKなら「ユーザーの作成」
(3)アクセスキーとシークレットキーをメモ
*Herokuとかの設定で使うと思うのでメモっといた方が良いと思います。
詳しくはこちら
まとめ
AWSは慣れないとよくわからないですね・・・
細かく設定すればもっと色々できるんだと思いますが、
まだよくわかっていないので、今回はここまでで止めておきます。
関連記事
Amazon S3の新しいバケットを作る。
こんにちは、マリンです。
サイトでの画像登録用にAWSのS3を使ったので、
その時の手順をメモっときます。
前提
AWSのアカウントは取得済み
途中の細かい設定はまだよくわからなので飛ばしてます。
手順
(1)サービスでS3を選択し、「バケットを作成する」をクリック。
(2)バケット名、リージョンを決定。
(3)プロパティとアクセス制限は「次へ」
*設定される方はきちんと設定してあげてください。私は飛ばしてます(笑)
(4)最後に確認して良ければ「バケットを作成」
*私の使ってるスクショの様子がおかしく、画像の下の方がダブってますが、本来はきちんと表示されています。見づらくて申し訳ありません。
まとめ
ただ作るだけなら特に問題はないですね。
リージョンの意味がわからなくて無駄に調べちゃいましたが…
次はこのS3ようのIAMを作ろうと思います。
画像が表示されないからfogとかS3とか使う。
こんにちは、マリンです。
早速問題発生しました。
ポートフォリオの画像が、一瞬表示されるのに気づいたら消えてる!?
調べてみたら、Herokuは画像データを保存できないので、
クラウドストレージがマストだとのこと。
Rails Tutorialの13.4.4「本番環境での画像アップロード」ところです。
「上手くいかなかったらここ飛ばしちゃっていいよ〜👍」なんて書いてあったけど、
飛ばしたら全然ダメじゃん!!(えぇ。私は飛ばしましたとも。)
Heroku使って本番運用をお考えの方はサラッとでも見とくことをオススメします。
と言うことで、今更ながら13章を見直した話しです。
13.4.4 本番環境での画像アップロードです。 railstutorial.jp
fog
まずはfog gemから。Gemfileに追加して$bundle install
です。
gem 'fog'
fogはRubyでクラウドサービスを使いやすくするためのGemです。
次に本番環境での画像ファイルの保存場所を変更します。
app/uploaders/○○_uploader.rb
を変更します。
if Rails.env.production? storage :fog else storage :file end
論理値を返すproduction?
メソッドで環境毎に保存先を変えられるようにします。
S3
S3はAWSのサービスの一つです。
*長くなるのでセットアップについては別記事で書こうと思います。
S3のセットアップが終了してからの設定です。
1. config/initializers
にcarrier_wave.rb
ファイルを作ります。
$touch config/initializers/carrier_wave.rb
2. CarrierWaveを通してS3を使う設定
if Rails.env.production? CarrierWave.configure do |config| config.fog_credentials = { # Amazon S3用の設定 :provider => 'AWS', :region => ENV['S3_REGION'], :aws_access_key_id => ENV['S3_ACCESS_KEY'], :aws_secret_access_key => ENV['S3_SECRET_KEY'] } config.fog_directory = ENV['S3_BUCKET'] end end
3. Herokuの環境変数を設定
AWSでIAMを作成した際のアクセスキー、シークレットキー、バケット名、レギオン(地域)を入力。
$ heroku config:set S3_ACCESS_KEY="Accessキーを入力" $ heroku config:set S3_SECRET_KEY="同様に、Secretキーを入力" $ heroku config:set S3_BUCKET="Bucketの名前を入力" $ heroku config:set S3_REGION="Regionの名前を入力"
4. .gitignoreを編集
ローカルの画像ファイルをGitの対象から外します。
. . . /public/uploads
5. デプロイします
$git add -A $git commit -m "hoge hoge" $git push $git push heroku $heroku run pg:reset DATABASE $heroku run rails db:migrate
データベースのリセットやサンプルデータがある場合などはご自身の環境に合わせて行ってください。
これで設定は完了です。
コケたところ
Herokuの環境変数についてよくわかっていなかったので、
REGION
の入力方法を間違えました。
さらにその間違えた変数を消去せずに正しいものを追加してしまったので、
ポートフォリオを全然追加できず、ハマってしまいました。
詳細
REGION
の値をS3の設定時に選択した「Asia pacific(Tokyo)」と入力。上記を削除することなく、追加で正規のリージョンを設定してしまう。
対処
1. 状況確認
まず全体的に意味がわからなかったので、とりあえず一覧表示させて状況を確認しました。
2. ダブり
上書きされてると勘違いしていたREGION
が正誤ダブっていることに気づいたので、
間違えた方を削除しました。
誤 -> Asia pacific(Tokyo)
正 -> ap-northeast-1
ちなみにS3でのRegionの表記についてはこちらに書かれています。
AWS のリージョンとエンドポイント - アマゾン ウェブ サービス
Herokuの環境変数について
- 環境変数の確認
一覧表示
$heroku config
変数名指定
$heroku config:get 環境変数名
- 環境変数の追加
$heroku config:set 環境変数名=値
- 環境変数の削除
$heroku config:unset 環境変数名
こちらのサイトを参考にさせていただきました。
まとめ
やはり一番大変だったのはAWS関係でした。
全く触ったことがない、名前しか知らないような状況でしたので・・・
今回行ったセットアップの方法については別記事で書こうと思います。
ここでは書かれていたことしかやっていないので氷山の一角だと思いますが、
かなり奥が深く、またとても便利なツールのようですね。
最近では結構必須な知識にもなっているようですし、
今までなんとなく避けていた分、これからきちんと勉強しようと思います。
追記
AWS系の方も記事書きましたのでよろしければどうぞ。
完成しました〜!!
いやぁ・・・長かったです。
たったこれだけのサイト作るのに1ヶ月かかってしまいましたorz
しかもほとんどtutorialパクっただけなのに・・・
しかし何はともあれ、無事完成し、デプロイも完了しました!
まだまだ改良の余地が満載なので、
今後少しずつでもよくしていこうと思います。
てか、仮でつけてた名前そのままであげちゃった・・・w
さて・・・次はアプリ作成に挑んでみようか?