Web Marina

日々の業務や勉強などで得た知識をアウトプットしていきます。

RSpecを学んでいて気付いた自分の弱点。

f:id:song-of-life1352607:20170220105406j:plain

こんにちは、マリンです。

この度アルバイト先が決まりまして、その会社で「RSpec使ってるから勉強しといて」と言われて今学んでおります。

今回の記事はただのぼやきです。すみません。

今回のテーマ

タイトルの通りです。

RSpecを勉強していて自分の決定的に足りない部分を見つけました。


RSpecについてはいろいろとサイトを巡って情報を集めており、

基本的な書き方は覚えました。

なので以前勉強したRails Tutorialを、今度はRSpecを使ってやってみようと思い立ったのですね。

だがしかし、全っ然出来ないんですよ!


テストが苦手なことは気づいていました。

正直、自分で楽しくやっていた時はスルーしてました。

でもまさかヒントがあるのに書けないとは・・・

そこで自分の最大の弱点に気づいたんです。

私の弱点

ズバリ、「応用力」です。

これが決定的に欠けています。

いや、数学がめっきりダメだった中学の頃から知ってはいたんですけど・・・


なんでテストが書けないかって考えてみると答えは簡単。

アプリ自体は結構そのまま使えたり、ほんのちょっと変えれば使えるようなコードが結構出てくるんですよね。

でもそれについてのテストコードまでは載ってないんです。

だから検索して出てきたコードを参考に自分のサイト作ったりはできますが、

それに対するテストは自分で考えなきゃだからできないんですね。


チュートリアルで基本は学びましたが、

そこから発展していざ自分で考えるとなると・・・

「え?どうすればいいんだっけ??」

となってしまうわけです。

で、どうすんの?

とはいえこのままでは使い物になりません。

そこで、なんで基本は学んだのに自分で考えて書けないのか?を考えてみました。

もちろん応用力が足りないからなんですけど・・・

その応用力に必要なものはなんだ?ともう一歩踏み込んで。


多分、「問題の本質を理解しているか?」だと思います。

目の前にある「〇〇をテストする」ということばかり考えて、

「え?どうやるの??」ってなっているから進まないのだと思うんですよね。

必要なのは、

「〇〇をテストする」

  1. 〇〇はどうやって動いているのか?
  2. どの部分をテストすれば良いのか?
  3. そのテストには何が必要なのか?

といった、〇〇という対象に対してもっと噛み砕いて構造や振る舞い、必要なものを考えないから、

何をしていいのか?がわからないんだと思いました。

前に勧められて読んだ本に書いてありましたが、

問題を解決するには、いかに噛み砕いて問題の本質を理解するかが鍵だそうです。


とはいえ・・・これ今から鍛えて間に合うのか???

と焦っています。

そしてそもそも圧倒的に足りない情報量・・・

どうしよう。

情報収集もしたいし、でもまだ基礎も完璧ではないし、

そして応用効かないし・・・

中学高校と「数学ムリ〜ww」とかヘラヘラしていた自分を呪います。

【Bootstrap4】navbarを2段にしてみた。

f:id:song-of-life1352607:20170220105406j:plain

こんにちは、マリンです。

大変おひさしぶりになってしまいました。

いろいろと仕事獲得のために動いてまして・・・

つまり何も進展がなくて書くことがなかっただけです。

今回「既存のHPを自由にレスポンシブしちゃって!」と言うとある課題を頂きましたので、

その時に行った表題の件です。



概要

基本、ホームページのスタイリングにはBootstrap4を使っております。

デフォルトのnavですが、ご存知の通りnavbar-brand含め左寄せです。

f:id:song-of-life1352607:20170603224850j:plain


これを画面の幅に合わせて、

広い時はロゴを上段、ナビを下段。

狭い時はインラインにしたいと思いました。

ついでにナビを中央揃えにします。

f:id:song-of-life1352607:20170603224747j:plain


float: none;じゃ上手くいかない!

いろいろ調べたのですが、Bootstrap3でのやり方ばかりで4の情報がなく、

それでは上手くいかなくて困り果てた挙句、本家のソースを見に行きました。

github.com




問題はこいつです!

  display: flex;




Bootstrap3まではfloatで位置を指定していたので、

float: none;でできたようなのですが、

4からはこのdisplay: flex;を使っているのでこいつが使えないのですね。


display: flex;とは?

CSS3から導入されたレイアウトモードです。

これまでfloatなどを使ってコンテンツをレイアウトしていたものを、

より柔軟に、かつ簡単にレイアウト出来るようになりました。

そしてレスポンシブデザインでも便利そうです。


詳しくはこちらをご覧ください。

www.webcreatorbox.com

まだ対応していないブラウザもあるようなのでご注意ください!


では本題です。


1. クラスを追加する

スタイルの上書きのためのclassを追加します。

追加するのはナビの一番の親に当たる<nav>です。

  <nav class="navbar navbar-toggleable-md navbar-light bg-faded gnav">

最後のgnavがそれです。(名前は任意)


2. スタイルを上書きする

追加したクラスにスタイルをあてます。

.gnav {
  flex-direction: column;
}

flex-direction : カラムをどの方向に並べるかを指定するプロパティです。

column : 文を改行した時に向う方向に並べます。わかりにくですが、通常上から下です。

値については他にもいろいろあるので調べてみてください。


以上です!

長い時間ハマったのが馬鹿みたいなくらい簡単でした・・・


詳しくはこちらをご覧ください。

http://scene-live.com/page.php?page=57




無事2段にはできましたが、

このままでは「ロゴが中央なのにナビは左寄せ」

という現象が起きます。(理由は後ほど)

なのでナビを中央揃えにします。


1. ulの幅を100%にする

ナビのリストを囲っているulの幅を100%にしてください。

ul {
  width: 100%;
}

これをやらないとこの後の処理をいくらやっても真ん中に入ってくれません。


2. クラスを追加する

中央寄せにするためのclassを追加します。

        <ul class="navbar-nav navbar-justified">

最後のnavbar-justifiedがそれです。(名前は任意)


3. スタイルを上書きする

追加したクラスにスタイルをあてます。

.navbar-justified {
  justify-content: center;
}

justifiy-content : コンテンツの横方向の位置を指定するプロパティです。

center : 中央揃えにします。

このほかに均等配置にするspace-betweenなどいろいろあります。


詳しくはこちらをご覧ください。

http://scene-live.com/page.php?page=59

これで無事に完了です!


ロゴが中央なのにナビは左寄せ

前にお話ししたこれです。

原因は2つあります。


原因1 : navbar-navにはコンテンツの配置指定がない

親の.navbarにはデフォルトでjustifiy-content: space-between;が指定されています。

しかし<ul>についてるクラスのnavbar-navにはついていません。

そのため、<ul>の範囲外のnavbar-brandであるロゴは中央配置になったのですね。


原因2 : ulの幅

原因1に気づいて一生懸命指定しましたが、最初うまくいきませんでした。

そこでデベロッパーツールで見てみると、

<ul>が左に寄って、かつ幅が狭かったのです。

その幅の中で真ん中にはなっているけど、

そもそもの幅が狭かったせいで全体の中央にこなかったのですね。


まとめ

今回は本当に良い勉強になりました!

何よりも、今までちんぷんかんぷんだった本家のソースとか見ちゃってる自分に感動ですw

でもフレームワークを使用する場合、

思ったようにならない時は元のソースを見ることも必要ですね。


補足

最終的なコードを載せておきます。

ただしこの記事を書いた当時のコードが残っていなかったことと、

Bootstrapのバージョンが上がったことで多少当時と変わっています。

付け焼き刃で急いで試したもので、改善が必要な点が多々あります。

後述しますのでそちらの注意もご覧ください。

<補足時の動作環境>

  • Rails5

  • Bootstrap 4.1.1

ソースコード

<nav class="navbar navbar-expand-lg navbar-light bg-light" style="flex-direction: column">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Link</a>
      </li>
      <li class="nav-item">
        <a class="nav-link disabled" href="#">Disabled</a>
      </li>
    </ul>
  </div>
</nav>

<変更点>

記事ではnavulにクラスをつけて、それぞれ2段にするスタイルと、

中央寄せにするスタイルをつけましたが、Bootstrap4.1.1で試したところ、

navに直接スタイルをつける方法でないとflex-direction: columnが効きませんでした。

おそらくnavについている.navbar-expand-lgと言うクラスのflex-directionが優先されているからと思われます。

!importantでいけるかと思いましたが、私の環境ではうまくいきませんでした。


次にulの方ですが、今回試したところわざわざ中央寄せのスタイルを書かなくても、

自動的に真ん中に寄ってくれました。

なので今回は削除してあります。


<注意点>

上記のコードでは画面を小さくした時のハンバーガーまで

2段の中央寄せになってします。

また、コンテンツの位置を手軽に設定できる

justify-content-~が使えると便利かと思ったのですが、

そちらは効きませんでした。


これらの改善点も一緒し修正したかったのですが、

まずは早急に補足を書きたかったので至らない点が多々あり申し訳ありません。

またいろいろと試してみてきちんと記事を書こうと思います。

binって何?railsとrakeって何??(後編)

f:id:song-of-life1352607:20170411225447p:plain

こんにちは、マリンです。


前回はよく見かけるbinとは何か?

そして、bin/railsファイルの中で行われていることが何か?を書きました。(今思えばちょっと趣旨がずれたかも・・・)


今回は、bin/rakeは何か?そしてrailsrakeの違いなどを書けたらなと思います。


前回の記事はこちらです。 song-of-life.hatenablog.com

bin/rakeとは?

まずは定番のRailsドキュメント様から。

Rakeとは Rubyで記述されたビルドツールです。

1行wwまぁそうなんでそうなんですけど・・・


ビルドツールとはソースコードを実行ファイルに変換したりするプロセスをやってくれるやつですね。コンパイルとか。

UNIX系でよく使われるという「make」がそれです。こっちはRubyだから「Rake」。

自分初心者なんで横文字の用語とかについてくのも必死なんですが、こういう語源とかにも何か大層な意味があるんじゃないかって気になっちゃうんですけど、意外と「え。そういうこと??」みたいのいっぱいありますよね(笑)


話しを元に戻しまして、つまりRakeはRubyで書かれた様々なタスクを呼び出して実行できる機能です。

で、問題はその「様々なタスク」に何があるのか?ですよね。

それはこちらのコマンドで確認できます。

$ rake -T

代表的なものがRailsドキュメントの解説にありますので見てみますと、

載っているのはrake db:migraterake db:rollbackrake db:seedrake aboutrake doc:apprake rails:updaterake db:createなどなど・・・


とってもたくさんありますが、何かデータベース系をいじるものが多い気がします。

他にもいっぱい載ってるんで見てみてください。

Rake - - Railsドキュメント

railsrakeの違い

前述した通り、rakeの説明としては「Rubyで記述されたビルドツール」ということでした。

railsについては、

アプリケーションに最低限必要なフォルダやファイルを自動的に作成

と書かれています。


何となく「タスクを実行する」っぽい感じは似てる気がしますが、その処理する分野が違うのかな?って感じです。

多分、そういうことではないかと・・・曖昧ですみません。違ってたらご指摘ください。

rakerailsに統合されてる

これですね。

Rails5からrakeタスクがrailsコマンドに統一されたそうです。ということで、今後はbin/rails一本で行けるということですかね。

紛らわしくなくて良いと思います!


ちなみに、Rakeのコマンドに入っていたrake doc:appとかrake doc:railsなんかのドキュメント作成系のタスクは削除されたそうです。

Ruby on Rails 5.0 リリースノート | Rails ガイド

bin/がついたりつかなかったり

binに戻ってきました。そもそもこれが原因で調べ始めたんですよね。

このbin/がついたりつかなかったりする現象については、こちらの記事で詳しく説明されていました。

qiita.com


どうやら4.1から標準装備になったSpringというものが関係しているようですね。

これまた調べ始めると長くなるので省略しますが、どうやらサーバの起動が早くなるようですね。

詳しくはこちらの記事をどうぞ。

Railsの開発効率をあげる - Springを使ってRailsのコンソールコマンドの実行を早くする - Rails Webook

Rails4.1 から入ったSpringって何よ? - kasei_sanのブログ



で最初の記事で検証されていたのは、それぞれのコマンドでbin/をつけた時とつけなかった時のSpringの状態がどうなっているか?ということです。


結論から言うと、railsコマンドではなくてもOK!rakeコマンドはないとダメ!ということでした。

Railsbin/railsファイルを優先的に起動する仕様になっているけど、bin/rakeファイルについてはbin/をつけないと素のrakeコマンドが実行されてしまい、rake -TとかはSpringを使わないからRailsが起動するまで待たなきゃいけないよ。

ということらしいです。


つまり、bin/rakeファイル内の処理を実行したい時はつけなきゃいけないんですね!「/」が入ってるからディレクトリの構造を示してはいるんだろうけど・・・とは思っていましたが、スッキリ。


で一つ前の項に書きましたが、Rails5では両者が統一されましたので、5以降を使用する場合はbin/もいらないし、rails一本だけでどちらのタスクも使えますよ!ということですね!!


はぁ〜!長かったけどやっとスッキリしたぁ!

ということで、長々とご覧いただきありがとうございました。

内容に間違いがございましたら是非ご指摘ください。よろしくお願い致します!

binって何?railsとrakeって何?(前編)

f:id:song-of-life1352607:20170411225447p:plain

こんにちは、マリンです。


アプリ開発していてわからないことがあると私はまずグーグル先生に聞きます。 多分大体の方がそうだと思いますが・・・

すると頻繁にこんな一文を見かけますよね。

$bin/rails ~

このbinって何だろうな?ってずっと気になっていたんですよね。


アプリの中にそういうディレクトリがあるのも知ってたんですが、詳細とか何が書かれているのかは今までスルーしてきました。(余計なこと調べるとハマるのでw)


でも今は取り急ぎやっていることもないので、いい機会だから調べてみました。

内容

binてよく見かけるけど、ついてる時とついてないときあるし、ついでにbin/railsとかbin/rakeとかあるけど・・・

binて何だ?railsrakeの違いってなんだ??について書こうと思います。

解説

binファイルとは?

まずはざっくりbinファイルってなんなのか調べてみました。

よくお世話になるIT用語辞典 e-Wordsさんではこのように書かれていました。

BINファイルとは、ファイル形式・拡張子の一つだが、標準化されたデータ形式ではなく、アプリケーション独自の形式で保存されたバイナリデータのファイル名の拡張子などによく使われる。“bin”は「バイナリ」(binary)の略号で、テキスト形式ではなくバイナリ形式であることを示している。

まだちょっと難しいですね。


こちらのサイト様でもっと簡単に書かれていました。(こちらもよくお世話になっております。)

wa3.i-3-i.info

binファイルとは通常バイナリデータが書かれていることが多いファイルで、バイナリデータというのはコンピュータが理解するためのプログラムが書かれたファイルということですか。


私はこの「バイナリデータ」の認識が間違っていたようですね。

画像とか音声を扱うファイルと思っていましたw

Railsアプリの中のbinディレクト

Rails Tutorialの1.3 最初のアプリケーションでは各ディレクトリのざっくりとした用途が書かれています。

bin/ バイナリ実行可能ファイル

やはりRailsに置いてもその用途は同じようですね。

binディレクトリの中身

ディレクトリの中身はこのようになっています。

bin/
┣bundle
rails
┣rake
┣setup
┣spring
┣update

bin/rails

今回はrailsコマンドとrakeコマンドの違いを知りたいので、その他のファイルは省略します。

なお、これ以降の内容はRailsガイドの「Railsの初期化プロセス」の中に詳しく書かれています。 railsguides.jp

あとこちらの記事も参考にさせていただきました。 shgam.hatenadiary.jp




bin/railsファイルの中身は以下のようになっています。

#!/usr/bin/env ruby
begin
  load File.expand_path('../spring', __FILE__)
rescue LoadError => e
  raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
  • #!/usr/bin/env ruby
    • #!は「shebang(シバン)」といい、インタプリタを指定するための文を表します。railsと言うファイルをrubyで解釈して欲しいので、この場合/usr/bin/env rubyという文でrubyインタプリタを使用することを指示しています。


  • begin~rescue~end
    • この間は例外処理です。springファイルがLoadErrorになった場合の処理のようです。


  • APP_PATH~
    • APP_PATHにパスを入れています。このあとに呼び出されるrails/commandsの中で使用されるようです。

    • File.expand_pathは、相対パス絶対パスに変換してくれます。第2引数の__dir__相対パスの基準となるディレクトリです。


  • require_relative'config/boot.rb'
    • require_relativeとすることで、ファイルの相対パスを指定して読み込むことができるそうです。

<boot.rbの中身>

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)

require 'bundler/setup' # Set up gems listed in the Gemfile. 
  • ENV[~
    • 環境変数BUNDLE_GEMFILEにGemfileのパスを入れています。 ||=が付いているので、「もし入っていなければ入れる」という指示です。
  • require~
    • bundler/setuprequireします。
    • このbundler/setupは、Gemfileにある依存ファイルが置かれている読み込みパスをBundlerで設定する際に使用されます。

つまり、このboot.rbファイルで、Gemfile内のGemをBundlerでセットアップをする指示を出しているということでしょうか・・・


ちなみに、RailsガイドではrequireがGemfileが存在する場合に実行されるようif文によって書かれていますが、私のファイルにはなかったです。 Gemfileが存在しないってことがまずないから無くなったのでしょうか??


bin/railsに戻って、 * require'rails/commands' * boot.rbファイルの次はcommands.rbファイルがrequireされます。 * このファイルにはコマンドの別名を拡張するためのコードが書かれています。つまり、serversと略せるようになるのはこのファイルのおかげです。

ARGV << '--help' if ARGV.empty?
 
aliases = {
  "g"  => "generate",
  "d"  => "destroy",
  "c"  => "console"
  "s"  => "server",
  "db" => "dbconsole"
  "r"  => "runner"
}
 
command = ARGV.shift
command = aliases[command] || command
 
require 'rails/commands/commands_tasks'
 
Rails::CommandsTasks.new(ARGV).run_command!(command)

コマンドの省略形に対する処理をした後、コマンドを実行する流れのようです。


長くなってきたので、続きは次回にします。

これまでの内容で誤りがありましたら是非ご指摘ください。

Rails プラグインを学んでみる。(後編)

f:id:song-of-life1352607:20170411225447p:plain

こんにちは、マリンです。


前回はRailsガイドの「プラグイン作成入門」の3まで書きました。今回は続きの4から書きます。


前回の記事はこちら。

song-of-life.hatenablog.com

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 プラグインを学んでみる。(前編)

f:id:song-of-life1352607:20170411225447p:plain

こんにちは、マリンです。

ポートフォリオサイトのスマホ化がひと段落しましたので、今度はブログ機能をつけようと思います。

せっかくなので、以前ちょこっと触れたプラグインをやってみようと思い、現在RailsガイドさんのRails プラグイン作成入門を勉強しています。

ここまでの内容を勉強ノートとしてまとめ。

PluginとEngine

本文とは少し外れますが、前回触れたのがエンジンで、今勉強中なのがプラグインで・・・

何が違うの?と思ったのでちょっと調べました。

Plugin

  • コアフレームワークを拡張したり変更したりするのに使う。

  • gemとしてビルドするので、RubygemsとBundlerを使用して他のRailsアプリケーションと共有することが可能。

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した時にエラーになってしまうので、ここを修正してください。

その後、プラグインディレクトリにてrake testです。

ダミーアプリの中ではrails test

プラグインディレクトリではrakeです。

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に追加する」から書きます。

サイトをスマホ対応にする

f:id:song-of-life1352607:20170221152659j:plain

こんにちは、マリンです。

今回作ったサイト、最初からレスポンシブ対応にしていたつもりだったのですが、

いざ本番で動かしてみたらスマホ対応にはなっていなかったようです。

そこで今回、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を入れないように記述するとうまくいきました。

satolabo.0t0.jp

まとめ

Bootstrapのレスポンシブ対応=スマホ対応と勘違いしていたことがそもそもの間違いでした。

でもこのVariantの導入でかなり楽にできるようになったようですね。

言語の発展で自動的にやってくれることがたくさんあるため、ついつい忘れてしまいますが、

本来ならコンピュータには1~10まで全て指示しなければいけないんですよね。

どこまでやってくれて、どこから自分でやらなければならないのか、

それもきちんと把握する必要がありそうです。