おぴよの気まぐれ日記

おぴよの気まぐれ日記

岡山やプログラミング、ファッションのこと、子育てや人生、生き方についての備忘録。

【bootstrap3】ナビゲーションバー(Navbar)で起きたレイアウト崩れと右寄せへの対応方法

こんばんは。opiyoです。

結論としては勝手な解釈をして余計なことしてた!に尽きるのだけど、同じようなハマり方すると時間もったい無いので共有です。

<header>
  <nav class="navbar navbar-inverse">
      <div class="container-fluid">
          <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbarEexample1">
                  <span class="sr-only">Toggle navigation</span>
          <% if logged_in? %>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
          <% else %>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          <% end %>
              </button>
              <a class="navbar-brand" href="#">
          <%= link_to "RChannel", root_path, id: 'logo' %>
              </a>
          </div>
          <div class="collapse navbar-collapse" id="navbarEexample1">
              <ul class="nav navbar-nav navbar-right">
          <% if logged_in? %>
            <li class="inline-block"><%= link_to "キーワード登録", new_user_keyword_path(user_id: @current_user.id) %></li>
            <p class="navbar-text inline-block"><%= @current_user.name %> さん</p>
            <li class="inline-block"><%= link_to "マイリスト", my_list_topic_path(id: @current_user.id) %></li>
            <li class="inline-block"><%= link_to "ログアウト", logout_path, method: :delete %></li>
          <% else %>
            <li class="inline-block"><%= link_to "アカウント登録", new_user_path %></li>
            <li class="inline-block"><%= link_to "ログイン", login_path %></li>
          <% end %>
              </ul>
          </div>
      </div>
  </nav>
</header>

ポイントはサンプル通りそのまま記載してください!

で僕が何をしていたのかご覧ください。

画面小さくした時に文字が隠れない

header側にもリンクが必要だと思ったんだよ。

          <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbarEexample4">
                  <span class="sr-only">Toggle navigation</span>
          <% if logged_in? %>
                    <span class="icon-bar"><%= link_to "キーワード登録", new_user_keyword_path(user_id: @current_user.id) %></span>
                    <span class="icon-bar"><%= link_to "マイリスト", my_list_topic_path(id: @current_user.id) %></span>
                    <span class="icon-bar"><%= link_to "ログアウト", logout_path, method: :delete %></span>
          <% else %>
            <span class="icon-bar"><%= link_to "アカウント登録", new_user_path %></span>
            <span class="icon-bar"><%= link_to "ログイン", login_path %></span>
          <% end %>
              </button>
              <a class="navbar-brand" href="#">
          <%= link_to "RChannel", root_path, id: 'logo' %>
              </a>
          </div>

最初こんな感じで.navbar-headerspanタグにもリンクが必要だと思って記載していたのですが、これやるとレイアウトが崩れます!

f:id:opiyotan:20180202201534p:plain

なので、spanタグには何も書いてはいけません!

左寄せが出来ない

          <div class="collapse navbar-collapse" id="navbarEexample1">
              <ul class="nav navbar-nav">
          <% if logged_in? %>
            <li class="inline-block navbar-right"><%= link_to "キーワード登録", new_user_keyword_path(user_id: @current_user.id) %></li>
            <p class="navbar-text inline-block navbar-right"><%= @current_user.name %> さん</p>
            <li class="inline-block"><%= link_to "マイリスト", my_list_topic_path(id: @current_user.id) %></li>
            <li class="inline-block"><%= link_to "ログアウト", logout_path, method: :delete %></li>
          <% else %>
            <li class="inline-block navbar-right"><%= link_to "アカウント登録", new_user_path %></li>
            <li class="inline-block navbar-right"><%= link_to "ログイン", login_path %></li>
          <% end %>
              </ul>
          </div>

サンプル見ると、pタグにnavbar-right設定しているから真似してたのだけど全然右寄せにならない。

で、Chromeで確認してみると

f:id:opiyotan:20180202201709p:plain

分かりづらいけど、既に領域が固定されているからfloatかけたって無駄。 なので、上の要素divタグに対して.navbar-rightを設定してやることでうまくいった!

まとめ

勝手な解釈はせずに、基本に忠実にやりましょう!

【Rails】XX件以上登録できないようにする独自バリデーションメソッドを設定する方法

こんばんは。opiyoです。

Railsアプリで「XX以上は登録できない!」というバリデーションを設定したかったので、やり方を調べてみました。

やりたいこと

Keywordというテーブルにデータを登録する処理で、5つまでしか登録できないようにバリデーションを設定します。

もし5つ以上の登録を行おうとした場合はsaveでエラーになるようにします。

Model

class Keyword < ApplicationRecord
  validates :title, presence: true
  validates :url, presence: true
  validate :check_count

  def check_count
    errors.add(:keyword, "は5つまで登録可能です。") if Keyword.count >= 5
    # errors.add(:keyword, "は5つまで登録可能です。") if Keyword.where(user_id: self.user_id).count >= 5
  end
end

モデルにバリデーションメソッドを定義します。 validateにメソッド名を記述し、そのメソッド内でKeywordの件数を取得しif文を記述します。 もし5件以上あれば、errorsの中に名前とエラーメッセージを追加します。

またコメントアウトしている部分ですが、selfを使うことで自分が登録したデータのみを対象とすることが出来ます。こうやって使うことが基本になりそうですね。

また、errorsの正体についてはActiveModel::Errorsで詳細はこちらを。

Controller

class KeywordsController < ApplicationController
  def create
    @keyword = Keyword.new(keyword_params)
    @keyword.check_count

    if @keyword.save
      redirect_to root_url
    else
      render 'new'
    end
  end

  private
    def keyword_params
      params.require(:keyword).permit(:title, :url)
    end
end

コントローラーではKeywordをインスタンス化して、メソッドを呼び出すだけです。 5件以上ある場合はerrorsにエラーが追加されているので、saveする時に失敗します。

という流れです。

【Bootstrap】navbarの背景色、文字色の悩みはこれ一発で解決だわー

何か作る時bootstrapにお世話になることあると思うのですが、cssいじっただけだと何故か上手くいかない。

例えば今回のnavbarですね。

ナビゲーションメニューがかっこよく決まらないとモチベーションが全く上がらないので、いろいろ探していたらあったわー。神様が。 https://work.smarchal.com/twbscolor/

自分の好きなカラーコードを入力したら勝手にcssのコード吐き出してくれる。

  • scss
  • sass
  • less
  • css

全部あるよ。

OhkEventRails.png

haml

    .navbar.navbar-default.navbar-static-top
      .container
        %button.navbar-toggle(type="button" data-toggle="collapse" data-target=".navbar-responsive-collapse")
          %span.icon-bar
          %span.icon-bar
          %span.icon-bar
        %a.navbar-brand(href="#") ホーム
        .navbar-collapse.collapse.navbar-responsive-collapse
          %ul.nav.navbar-nav
            %li= link_to "Link 1", "/path1"
            %li= link_to "Link 2", "/path2"
            %li= link_to "Link 3", "/path3"

scss

$bgDefault      : #dd4444;
$bgHighlight    : #e8350e;
$colDefault     : #ecf0f1;
$colHighlight   : #ecdbff;
$dropDown       : false;

.navbar-default {
  background-color: $bgDefault;
  border-color: $bgHighlight;
  .navbar-brand {
    color: $colDefault;
    &:hover, &:focus {
      color: $colHighlight; }}
  .navbar-text {
    color: $colDefault; }
  .navbar-nav {
    > li {
      > a {
        color: $colDefault;
        &:hover,  &:focus {
          color: $colHighlight; }}
      @if $dropDown {
        > .dropdown-menu {
          background-color: $bgDefault;
          > li {
            > a {
              color: $colDefault;
              &:hover,  &:focus {
                color: $colHighlight;
                background-color: $bgHighlight; }}
            > .divider {
              background-color: $bgHighlight;}}}}}
    @if $dropDown {
      .open .dropdown-menu > .active {
        > a, > a:hover, > a:focus {
          color: $colHighlight;
          background-color: $bgHighlight; }}}
    > .active {
      > a, > a:hover, > a:focus {
        color: $colHighlight;
        background-color: $bgHighlight; }}
    > .open {
      > a, > a:hover, > a:focus {
        color: $colHighlight;
        background-color: $bgHighlight; }}}
  .navbar-toggle {
    border-color: $bgHighlight;
    &:hover, &:focus {
      background-color: $bgHighlight; }
    .icon-bar {
      background-color: $colDefault; }}
  .navbar-collapse,
  .navbar-form {
    border-color: $colDefault; }
  .navbar-link {
    color: $colDefault;
    &:hover {
      color: $colHighlight; }}}
@media (max-width: 767px) {
  .navbar-default .navbar-nav .open .dropdown-menu {
    > li > a {
      color: $colDefault;
      &:hover, &:focus {
        color: $colHighlight; }}
    > .active {
      > a, > a:hover, > a:focus {
        color: $colHighlight;
        background-color: $bgHighlight; }}}
}

【Rails】ファイルをデータベースに保存する方法

ファイルを保存する方法はRailsチュートリアルとかでは、CarrierWaveというgemを使う。 だがちょっとしたアプリとか作りたい時には、DBに保存した方が都合がいい時もあるはず。

gemを使う方法は別の機会でまとめるとして、今日はDBに保存する方法を。

モデルを作る

$ rails g model Image name:string picture:binary
  invoke  active_record
  create    db/migrate/20171215092903_create_images.rb
  create    app/models/image.rb
# migrate
class CreateImages < ActiveRecord::Migration[5.0]
  def change
    create_table :images do |t|
      t.string :name
      t.binary :picture

      t.timestamps
    end
  end
end
$ rails db:migrate
== 20171215092903 CreateImages: migrating =====================================
-- create_table(:images)
   -> 0.3369s
== 20171215092903 CreateImages: migrated (0.3370s) ============================

コントラーラーを作る

$ rails g controller Images
Running via Spring preloader in process 7555
      create  app/controllers/images_controller.rb
      invoke  erb
      create    app/views/images
      invoke  helper
      create    app/helpers/images_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/images.coffee
      invoke    scss
      create      app/assets/stylesheets/images.scss
# images_controller.rb
class ImagesController < ApplicationController
  def new
    @image = Image.new
    @image.name = "hogehoge"
  end

  def create
    @image = Image.new(image_paprams)
    @image.name = params[:image][:picture].original_filename
    @image.picture = params[:image][:picture].read

    if @image.save
      redirect_to root_path
    else
      render 'new'
    end
  end

  private

    def image_paprams
      params.require(:image).permit(:name, :picture)
    end

end

ビューを作る

# new.html.erb
<%= form_for(@image) do |f| %>
  <div class="form-group">
    <%= @image.name %>
    <%= f.file_field :picture %>
    <%= f.submit "画像を投稿する" %>
  </div>
<% end %>

↓htmlに変換されると...

<form class="new_image" id="new_image" enctype="multipart/form-data" action="/images" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="ZgO8WthU8KtI/rspO/oVgHavcwUUVQl1jDwm0DQAsZXwCHYLO02KUqcX+Kt54gKlUlQP4sqDe3NUltVWjtZQDw==">
  <div class="form-group">
    hogehoge
    <input type="file" name="image[picture]" id="image_picture">
    <input type="submit" name="commit" value="画像を投稿する" data-disable-with="画像を投稿する" disabled="">
  </div>
</form>

まとめ

こんな感じでしょうか。 とりあえず言いたいことは、

  • binary型のカラムをモデルに用意します。
  • form_forf.file_fieldを使います。
  • params[:image][:picture].readで画像データが保存できる

form_forがよしなにやってくれるのは分かるのだけど、いまいち理解が浅いので色々動かしてみて勉強しよう。

で、実際に登録された画像データはこんな感じです。

$ rails c
> Image.all
  Image Load (1.6ms)  SELECT "images".* FROM "images"
=> #<ActiveRecord::Relation [#<Image id: 1, name: "17704-koala-bear-pv.jpg", picture: "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xFF\xDB\x00C\x00\n\a\a\b\a\x06\n\b\b\b\v\n\n\v\x0E\x18\x10\x0E\r\r\x0E\x1D\x15\x16\x11...", created_at: "2017-12-15 09:52:29", updated_at: "2017-12-15 09:52:29">]>

【Ruby on Rails】月の最初の日、最終日はどうやって取得する?

画面から入力された日付の月が何日までなのか取得する方法が分からなかったので調べてみました。

月の最終日

irb> Date
NameError: uninitialized constant Date
Did you mean?  Data
    from (irb):9
    from /Users/taku/.rbenv/versions/2.3.3/bin/irb:11:in `<main>'

irb> require "date"
=> true

irb> date = Date.today
=> #<Date: 2017-12-13 ((2458101j,0s,0n),+0s,2299161j)>

irb> date.end_of_month
NoMethodError: undefined method `end_of_month' for #<Date: 2017-12-13 ((2458101j,0s,0n),+0s,2299161j)>
  from (irb):13
  from /Users/taku/.rbenv/versions/2.3.3/bin/irb:11:in `<main>'

むむむ何でだ。 end_of_monthというメソッドを使うと月の最終日が取れる。取れたんだけど...

調べてみると、end_of_monthはRailsで定義されたメソッドみたい。 なのでrails cで検証スタート。

> rails c

> date = Date.today
=> Wed, 13 Dec 2017

> date.end_of_month
=> Sun, 31 Dec 2017

> date.end_of_month.to_s
=> "2017-12-31"

月の最初の日

月の最初の日を求める時はbeginning_of_monthを使う

> date = Date.today
=> Wed, 13 Dec 2017

> date.beginning_of_month
=> Fri, 01 Dec 2017

> date.beginning_of_month.to_s
=> "2017-12-01"

その他のちょっとしたあれこれ

> Date.today.year
=> 2017

> Date.today.month
=> 12

> Date.today.day
=> 13

> Date.today.wday
=> 3 # 「0」が日曜日なので「3」は水曜日

【Rails】created_atとupdated_atへデータを登録する方法

過去データの取り込みで直接DBにデータを入れる際にcreated_atupdated_atにはどうやって値をセットすれば良いのか分からなかったから調べてみた。

結論としてはTimeWithZoneクラスが使われているからTime.zone.nowすれば良いっぽい。

> Shop.first.created_at.class
  Shop Load (0.9ms)  SELECT  "shops".* FROM "shops" WHERE "shops"."deleted_at" IS NULL  ORDER BY "shops"."id" ASC LIMIT 1
=> ActiveSupport::TimeWithZone

TimeWithZone?

使い方はこんな感じ。 http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html

> Time.zone = 'Eastern Time (US & Canada)'
=> "Eastern Time (US & Canada)"
> Time.zone.now
=> Mon, 18 Dec 2017 01:17:43 EST -05:00

> Time.zone = "Asia/Tokyo"
=> "Asia/Tokyo"
> Time.zone.now
=> Mon, 18 Dec 2017 15:17:52 JST +09:00
> Time.zone.now.to_s
=> "2017-12-18 15:18:31 +0900"

> Time.zone.local(2012,12,31,15,30,00)
=> Mon, 31 Dec 2012 15:30:00 JST +09:00
> Time.zone.local(2012,12,31,15,30,00).to_s
=> "2012-12-31 15:30:00 +0900"

> Time.zone.parse('2013-12-31 15:30:00')
=> Tue, 31 Dec 2013 15:30:00 JST +09:00
> Time.zone.parse('2013-12-31 15:30:00').to_s
=> "2013-12-31 15:30:00 +0900"

その他の使い方は

> t = Time.zone.now
=> Mon, 18 Dec 2017 17:53:08 JST +09:00
> t.year
=> 2017
> t.month
=> 12
> t.day
=> 18
> t.hour
=> 17
> t.min
=> 53
> t.sec
=> 8

> t.zone
=> "JST"
> t.to_s
=> "2017-12-18 17:53:08 +0900"
> t + 1.day
=> Tue, 19 Dec 2017 17:53:08 JST +09:00
> (t + 1.day).to_s
=> "2017-12-19 17:53:08 +0900"
> t.beginning_of_year
=> Sun, 01 Jan 2017 00:00:00 JST +09:00
> t.ago(1.day)
=> Sun, 17 Dec 2017 17:53:08 JST +09:00
> t.ago(1.day).to_s
=> "2017-12-17 17:53:08 +0900"
> t.inspect
=> "Mon, 18 Dec 2017 17:53:08 JST +09:00"
> t.to_a
=> [8, 53, 17, 18, 12, 2017, 1, 352, false, "JST"]

で、UTCってなんだってなったのでメモ。

「UTC(協定世界時)」とは、世界各地の標準時を決めるときの基準となる「世界標準時」のことです。たとえば日本の標準時(JST)は「UTC」よりも 9時間進んでいるため「UTC+09:00」と表示されます。 http://www.724685.com/word/wd140611.html

UTCは世界標準の時間で、日本の場合はJSTで9時間ずれてるから+9するのですね。 納得。

【Rails環境構築】bundle installでエラーになる時の対処法!

こんにちは。opiyoです。

  • 昨日まで普通に動いていたのに
  • 教科書、本と通りに設定しているはずなのに
  • 何もしてないのに動かないぞー

って経験無いでしょうか?

僕も昨日新しくMacが手に入ったのでRails環境をローカルに構築して今作っているRailsアプリを動かそうとしたら...


2時間近くはまってしまいました。

元々使ってたMacと全く同じ設定のはずなのに何故動かないんだーって状況でした。

どうにかこうにか解決する事が出来たので、その方法について共有できればと思います。

エラーが出た時に「どうすれば良いか」が分からなくて諦めてしまう。ってのが結構あると思うのですが答えは必ずエラーの中に書かれている ので頑張ってGoogle翻訳使って一つずつ解決していくのが大事だと思いますので僕がどうやって進めていったのかのログです。

動かしたいRailsアプリについて

僕の場合は、こんな感じ。

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin15]

$ rails -v
Rails 5.1.4

bundle installができない

$ bundle install

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pg-0.21.0/ext
/Users/tnakano/.rbenv/versions/2.5.0/bin/ruby -r ./siteconf20180125-28967-e942ot.rb extconf.rb
checking for pg_config... no
No pg_config... trying anyway. If building fails, please try again with
 --with-pg-config=/path/to/pg_config
checking for libpq-fe.h... no
Can't find the 'libpq-fe.h header
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/Users/tnakano/.rbenv/versions/2.5.0/bin/$(RUBY_BASE_NAME)
    --with-pg
    --without-pg
    --enable-windows-cross
    --disable-windows-cross
    --with-pg-config
    --without-pg-config
    --with-pg_config
    --without-pg_config
    --with-pg-dir
    --without-pg-dir
    --with-pg-include
    --without-pg-include=${pg-dir}/include
    --with-pg-lib
    --without-pg-lib=${pg-dir}/lib

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-16/2.5.0-static/pg-0.21.0/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/pg-0.21.0 for inspection.
Results logged to /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-16/2.5.0-static/pg-0.21.0/gem_make.out

An error occurred while installing pg (0.21.0), and Bundler cannot continue.
Make sure that `gem install pg -v '0.21.0'` succeeds before bundling.

In Gemfile:
  pg

これだけ見ても何が何だか分からないですよね。 ですが諦めずに良く良く表示されたメッセージを見てください。

ポイントは最後辺りのMake sure thatgem install pg -v '0.21.0'succeeds before bundling.ですね。

直訳するとバンドルの前にgem install pg -v '0.21.0'が成功していることを確認してください。`になります。

じゃー次にgem pgって何だってなると思いますので、これを調べてみるとPostgreSQLにアクセスするために必要なことだと分かります。

「あっそもそもPostgreSQLインストールしてねーじゃん」ってことに僕は気づきましたので、PostgreSQLをインストールします。

postgresqlをインストールする

$ brew install postgresql
==> Installing postgresql

PostgreSQLがインストール出来たので、もっかいbundle install実行!

$ bundle install
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/rmagick-2.16.0/ext/RMagick
/Users/tnakano/.rbenv/versions/2.5.0/bin/ruby -r ./siteconf20180125-42802-14ohnoi.rb extconf.rb
checking for clang... yes
checking for Magick-config... no
checking for pkg-config... yes
Package MagickCore was not found in the pkg-config search path.
Perhaps you should add the directory containing `MagickCore.pc'
to the PKG_CONFIG_PATH environment variable
No package 'MagickCore' found
checking for outdated ImageMagick version (<= 6.4.9)... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/Users/tnakano/.rbenv/versions/2.5.0/bin/$(RUBY_BASE_NAME)

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-16/2.5.0-static/rmagick-2.16.0/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/rmagick-2.16.0 for inspection.
Results logged to /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-16/2.5.0-static/rmagick-2.16.0/gem_make.out

An error occurred while installing rmagick (2.16.0), and Bundler cannot continue.
Make sure that `gem install rmagick -v '2.16.0'` succeeds before bundling.

In Gemfile:
  rmagick

おーエラーの内容が変わりましたね。一歩前進です。

次にエラーになっている原因を探すと、さっきと同じようなメッセージが出ていますね。

Make sure thatgem install rmagick -v '2.16.0'succeeds before bundling.これを直訳するとバンドルする前にgem install rmagick -v '2.16.0'が成功していることを確認してください。ってなります。

同じようにgem rmagickを調べて解決方法を探します。するとImagemagickってのをインストールしないといけないっぽいですね。

という感じで表示されたメッセージを良く読んで、エラー文をそのままGoogleさんに聞くと同じように悩んで解決したって記事がいっぱい見つかると思うので一つずつ試していきます。

imagemagickがインストールできない

$ brew install imagemagick
==> Installing imagemagick

Imagemagickがインストール出来たので、もっかいbundle install実行します。

$ bundle install
.
.
.
checking for outdated ImageMagick version (<= 6.4.9)... no
checking for presence of MagickWand API (ImageMagick version >= 6.9.0)... no
checking for Ruby version >= 1.8.5... yes

またエラーになりますね。

なんだかこの辺りが怪しそうなので、色々調べてみるとImageMagickのバージョンが7系だとダメみたい。

$ convert --version
Version: ImageMagick 7.0.7-22 Q16 x86_64 2018-01-22 http://www.imagemagick.org

うん。ダメぽ。

$ brew uninstall imagemagick
Uninstalling /usr/local/Cellar/imagemagick/7.0.7-22... (1,527 files, 23.3MB)
$ convert --version
-bash: /usr/local/bin/convert: No such file or directory

うん。削除できてるっぽいですね。

$ brew install imagemagick@6
==> Downloading https://homebrew.bintray.com/bottles/imagemagick@6-6.9.9-34.sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring imagemagick@6-6.9.9-34.sierra.bottle.tar.gz
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have this software first in your PATH run:
  echo 'export PATH="/usr/local/opt/imagemagick@6/bin:$PATH"' >> ~/.bash_profile

For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/imagemagick@6/lib
    CPPFLAGS: -I/usr/local/opt/imagemagick@6/include
For pkg-config to find this software you may need to set:
    PKG_CONFIG_PATH: /usr/local/opt/imagemagick@6/lib/pkgconfig

==> Summary
🍺  /usr/local/Cellar/imagemagick@6/6.9.9-34: 1,472 files, 22.8MB
$ convert --version
-bash: /usr/local/bin/convert: No such file or directory

あれっなんだ。おかしいぞ。 もっかい見直してみる。

This formula is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have this software first in your PATH run:
  echo 'export PATH="/usr/local/opt/imagemagick@6/bin:$PATH"' >> ~/.bash_profile

For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/imagemagick@6/lib
    CPPFLAGS: -I/usr/local/opt/imagemagick@6/include
For pkg-config to find this software you may need to set:
    PKG_CONFIG_PATH: /usr/local/opt/imagemagick@6/lib/pkgconfig

この辺りがエラーだろう。とりあえず翻訳だー

この式はkeg-onlyであり、/ usr / localにシンボリックリンクされていないことを意味し、
これは別の式の代替バージョンであるためです。

PATHでこのソフトウェアを最初に実行する必要がある場合:
  echo 'export PATH = "/ usr / local / opt / imagemagick @ 6 / bin:$ PATH"' >>〜/ .bash_profile

ふむふむ。パスが通ってないってことだと思うので...

$ echo 'export PATH="/usr/local/opt/imagemagick@6/bin:$PATH"' >> ~/.bash_profile
$ source .bash_profile

もっかいimagemagickをインストール

$ brew uninstall imagemagick@6
$ brew install imagemagick@6
$ convert --version
Version: ImageMagick 6.9.9-34 Q16 x86_64 2018-01-22 http://www.imagemagick.org

よしよし。これで6.9になったのでもっかい

$ bundle install
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/tnakano/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/rmagick-2.16.0/ext/RMagick
/Users/tnakano/.rbenv/versions/2.5.0/bin/ruby -r ./siteconf20180125-47095-pm8xl8.rb extconf.rb
checking for clang... yes
checking for Magick-config... yes
checking for outdated ImageMagick version (<= 6.4.9)... no
checking for presence of MagickWand API (ImageMagick version >= 6.9.0)... no
Package MagickWand was not found in the pkg-config search path.
Perhaps you should add the directory containing `MagickWand.pc'
to the PKG_CONFIG_PATH environment variable
No package 'MagickWand' found
Package MagickWand was not found in the pkg-config search path.
Perhaps you should add the directory containing `MagickWand.pc'
to the PKG_CONFIG_PATH environment variable
No package 'MagickWand' found
Package MagickWand was not found in the pkg-config search path.
Perhaps you should add the directory containing `MagickWand.pc'
to the PKG_CONFIG_PATH environment variable
No package 'MagickWand' found
Package MagickWand was not found in the pkg-config search path.
Perhaps you should add the directory containing `MagickWand.pc'
to the PKG_CONFIG_PATH environment variable
No package 'MagickWand' found
.
.
An error occurred while installing rmagick (2.16.0), and Bundler cannot continue.
Make sure that `gem install rmagick -v '2.16.0'` succeeds before bundling.

In Gemfile:
  rmagick

くそーダメぽ。

もっかいエラーと睨めっこしてみるとPKG_CONFIG_PATHってのがNo言われてる。 これを設定すれば良いのか?

$ echo 'export PKG_CONFIG_PATH="/usr/local/opt/imagemagick@6/lib/pkgconfig"' >> ~/.bash_profile
$ source .bash_profile

今度こそ〜神様〜

$ bundle install
Installing rmagick 2.16.0 with native extensions
.
.
Bundle complete! 26 Gemfile dependencies, 95 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

できたー!!!!!

まとめ

ハマるポイントとしては

  • imagemagicは6系をインストールする必要がある!
  • インストールされた6系に対してパスを通してあげる必要がある
  • エラーをよく読む!

答えはいつも「エラー」にある!

英語大事...

初心者でも30分で出来た!MacにRails開発環境を作ってみた

こんばんは。opiyoです。

プログラマの勉強をしていて最初につまずくポイントは環境構築じゃないでしょうか?

今はCloud9とかWeb上で勉強できるサイトなどが当たり前になってきているので、作るきっかけは無いかもしれないですがエンジニアとして働いていく上で環境構築はきっと出来た方がいいはずです!

新しく会社に入った時を想像すると最初にやる仕事はきっと、渡されたMacに携わるプロジェクトの環境を構築する事だと思います。

という事で、今日は1から作業してみたいと思います。

このMacについて

  • OS X El Capitan(10.11.6)

Homebrewインストール

Homebrewは、Macでソフトウェアの導入を単純化するパッケージ管理システムだと。 これをインストールすることbrew hogeみたいな感じで簡単に色々なソフトウェアをダウンロードできる。

インストール方法は、ターミナルに以下のコマンドを貼り付けて実行する

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
.
.
.
==> Installation successful!

どんなバージョンが入っているかはbrewコマンドに-vオプション付けます。

$ brew -v
Homebrew 1.5.2

brewコマンドのパスを設定します

$ echo 'export PATH=/usr/local/bin:$PATH' >> .bash_profile
$ source .bash_profile

brewの最新バージョンを取得する場合はupdateします

$ brew update

これ以外にも沢山の事が出来るので操作方法をチェックするにはhelpで確認してみましょう!

$ brew help
Example usage:
  brew search [TEXT|/REGEX/]
  brew (info|home|options) [FORMULA...]
  brew install FORMULA...
  brew update
  brew upgrade [FORMULA...]
  brew uninstall FORMULA...
  brew list [FORMULA...]

Troubleshooting:
  brew config
  brew doctor
  brew install -vd FORMULA

Developers:
  brew create [URL [--no-fetch]]
  brew edit [FORMULA...]
  https://docs.brew.sh/Formula-Cookbook.html

Further help:
  man brew
  brew help [COMMAND]
  brew home

gitインストール

gitは、ソースコードのバージョン管理の仕組みです。 gitは普段仕事でも使っているのですが、インストールとか設定とか全然覚えていないので復習

インストールは先程のbrewコマンドを使って行います。 ついでにメールアドレスの設定も行います。  ※メールアドレスだけ設定しておけばgithubpushした際にgithubがよしなに解釈してくれます。

$ brew install git 
$ git --version
git version 2.16.1

$ git config --global user.email email@example.com

githelpを使うと使い方が出てきます。

$ git --help
usage: git [--version] [--help] [-C <path>] [-c name=value]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone      Clone a repository into a new directory
   init       Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add        Add file contents to the index
   mv         Move or rename a file, a directory, or a symlink
   reset      Reset current HEAD to the specified state
   rm         Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect     Use binary search to find the commit that introduced a bug
   grep       Print lines matching a pattern
   log        Show commit logs
   show       Show various types of objects
   status     Show the working tree status

grow, mark and tweak your common history
   branch     List, create, or delete branches
   checkout   Switch branches or restore working tree files
   commit     Record changes to the repository
   diff       Show changes between commits, commit and working tree, etc
   merge      Join two or more development histories together
   rebase     Reapply commits on top of another base tip
   tag        Create, list, delete or verify a tag object signed with GPG

collaborate (see also: git help workflows)
   fetch      Download objects and refs from another repository
   pull       Fetch from and integrate with another repository or a local branch
   push       Update remote refs along with associated objects

rbenvインストール

rbenvは複数のRubyのバージョンを切り替えて使う為の環境を提供してくれる。 プロジェクトによってバージョンが違う事があるからこれで管理するそうだ。

インストール方法は、先程のbrewを使う。 この時に、ruby-buildというRubyをインストールするプラグインも合わせてインストールする

$ brew install rbenv ruby-build

rbenvコマンドにパスを設定する

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> .bash_profile
$ echo 'eval "$(rbenv init -)"' >> .bash_profile
$ source .bash_profile

pathを設定する際に出てくる「$HOME」という奴は環境変数って奴です。 環境変数はプログラムの検索先を変数に入れて、毎回長いpathを打つのを省略してくれます。 今回であればrbenvの実行ファイルが格納されているディレクトリをPATHに追加しています。

Rubyインストール

次にインストール可能なRubyのバージョン一覧を表示する

¥ rbenv install --list

するとずらーっと表示されるので、最新のバージョンをインストールします。

今回であれば、2.5.0ですかね。

  2.3.6
  2.4.0-dev
  2.4.0-preview1
  2.4.0-preview2
  2.4.0-preview3
  2.4.0-rc1
  2.4.0
  2.4.1
  2.4.2
  2.4.3
  2.5.0-dev
  2.5.0-preview1
  2.5.0-rc1
  2.5.0
  2.6.0-dev
$ rbenv install 2.5.0

これが結構時間かかる。 で、終わったらインストールしたバージョンを使いますよーって宣言する

$ rbenv global 2.5.0
$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16]

ちなみにインストールしているバージョンを調べたい時は

$ rbenv versions
  system
* 2.5.0 (set by /Users/tnakano/.rbenv/version)

*が付いているのが今使われているrubyのバージョンです。

Railsインストール

では、最後にRailsをインストールします。

Railsプロジェクトを作りたい場所に移動してからインストール

$ cd ~/rails
$ gem install rails

bundler(Rubyのライブラリを管理するツール)のインストール

$ gem install bundler

インストールした内容を反映

$ rbenv rehash
$ source ~/.bash_profile

インストールできたか確認

$ rails -v
Rails 5.1.4

これで準備が整いましたー

せっかくなので、動く所までやってみよう。

Railsプロジェクト作成

¥ rails new sample
¥ cd sample
¥ rails s

rails s コマンドでwebサーバが起動するので、ブラウザを開いて「localhost:3000」にアクセスすると……

あっという間にRailsアプリが完成です。

Atom

最後に、開発エディタについてですが会社では皆RubyMineを使っているのですが無料のAtomを使いたいと思います。

インストール方法は、こちらからダウンロードするだけ。

https://atom.io/

まとめ

こんな感じで何もエラーにさえならなければ30分くらいで簡単に出来ると思いますので、皆様も是非Macに開発環境を作ってみると良いと思います。

お前何言ってんだよってのがありましたらご教授いただけますと幸いです。

【Ruby on Rails】スクレイピングで簡単にmeta情報を取得するgem metainspector

こんばんわ。エンジニアに夢を描くopiyoです。

最近はずっとスクレイピングについて触れることが多いのですが、こんな経験ないですか?

ブログ書く時とかurl貼り付けるだけで引用文が作成されるけど、あれどうやってんだ?

まさにこういう奴↓↓

opiyotan.hatenablog.com

多分ですが、これもスクレイピングで情報を引っ張ってきているはずなのです。

この情報を簡単に取得できちゃうgemを見っけたので今日は、それについて。

使う準備

こちらは、おなじみGemfileに`metainspector'を記述します。

gem 'metainspector'

こちらも、おなじみbundle installします。

$ bundle install

使い方

はてなブログのトップページにある記事から情報を取得したいと思います!

広島県 VS EM研究機構 - warbler’s diary

※なんだかお堅いサンプルになってしまいしたが...利用させて頂きます。ありがとうございます。

概要=descriptionを取得する

やり方は非常に簡単で取得したデータに対してdescriptionメソッドを呼ぶだけ。

meta = MetaInspector.new("http://warbler.hatenablog.com/entry/2018/01/24/011739")
puts meta.description
.
.
.
広島県からEM菌の水質浄化効果を否定する内容の報告書が出された事に対して、EM研究機構が抗議をしていました。 ・EM菌の培養液は有機物と栄養塩類が高濃度に含まれることから「河川等の汚染源になり得る」という実験結果を報告した福島県に対しても、EM研究機構を含むEM推進側が抗議をしていた事については、既に本ブログで報告して…

画像を取得する

こちらも非常に簡単で取得したデータからimages.bestするだけ。

meta = MetaInspector.new(url)
puts meta.images.best
.
.
.
=> "https://cdn-ak.f.st-hatena.com/images/fotolife/w/warbler/20180124/20180124001356.png"

その他

その他にも色々な情報を簡単に取得できるので、ざらっと書いてみます。

$ rails c
> meta.url
=> "http://warbler.hatenablog.com/entry/2018/01/24/011739"

> meta.host
=> "warbler.hatenablog.com"

> meta.head_links
=> [{:rel=>"canonical", :href=>"http://warbler.hatenablog.com/entry/2018/01/24/011739"}, {:rel=>"shortcut icon", :href=>"https://cdn.image.st-hatena.com/image/favicon/0c16e66ee260e69eb13510af1e9878996b545656/version=1/https:%2F%2Fcdn.user.blog.st-hatena.com%2Fcustom_blog_icon%2F36385751%2F1514183975459583"}, {:rel=>"icon", :sizes=>"192x192", :href=>"https://cdn.image.st-hatena.com/image/square/7fdc8aba078df5faff51cf50422005a5085822ff/backend=imagemagick;height=192;version=1;width=192/https:%2F%2Fcdn.user.blog.st-hatena.com%2Fcustom_blog_icon%2F36385751%2F1514183975459583"}, {:rel=>"alternate", :type=>"application/atom+xml", :title=>"Atom", :href=>"http://warbler.hatenablog.com/feed"}, {:rel=>"alternate", :type=>"application/rss+xml", :title=>"RSS2.0", :href=>"http://warbler.hatenablog.com/rss"}, {:rel=>"alternate", :type=>"application/json+oembed", :href=>"http://hatenablog.com/oembed?url=http://warbler.hatenablog.com/entry/2018/01/24/011739&format=json", :title=>"oEmbed Profile of 広島県 VS EM研究機構"}, {:rel=>"alternate", :type=>"text/xml+oembed", :href=>"http://hatenablog.com/oembed?url=http://warbler.hatenablog.com/entry/2018/01/24/011739&format=xml", :title=>"oEmbed Profile of 広島県 VS EM研究機構"}, {:rel=>"author", :href=>"http://www.hatena.ne.jp/warbler/"}, {:rel=>"stylesheet", :type=>"text/css", :href=>"https://cdn.blog.st-hatena.com/css/blog.css?version=16c4f762d17230c5653ead590e78f5c1c08b8f84&env=production"}, {:rel=>"stylesheet", :type=>"text/css", :href=>"http://blog.hatena.ne.jp/-/blog_style/6653586347156021977/567bb7d3aa205029bfc477b21f9e4dc351ef5eee"}]

> meta.feed
=> "http://warbler.hatenablog.com/rss"

> meta.title
=> "広島県 VS EM研究機構 - warbler’s diary"

> meta.links.raw
=> ["#", "http://warbler.hatenablog.com/", "http://warbler.hatenablog.com/archive/2018/01/24", "http://warbler.hatenablog.com/entry/2018/01/24/011739", "https://www.emro.co.jp/information/04_HH/", "http://www.pref.aomori.lg.jp/kenminno-koe/24K23.html", "http://b.hatena.ne.jp/entry/http://warbler.hatenablog.com/entry/2018/01/24/011739", "https://twitter.com/share", "http://warbler.hatenablog.com/entry/2018/01/23/235522", "http://warbler.hatenablog.com/archive/2018/01/23", "http://warbler.hatenablog.com/entry/20150227/1425057866", "http://warbler.hatenablog.com/archive/2015/02/27", "http://warbler.hatenablog.com/archive/2013/09/03", "http://warbler.hatenablog.com/entry/20130903/1378217975", "http://warbler.hatenablog.com/entry/20130712/1373632961", "http://warbler.hatenablog.com/archive/2013/07/12", "http://warbler.hatenablog.com/entry/20130428/1367131822", "http://warbler.hatenablog.com/archive/2013/04/28", "http://warbler.hatenablog.com/about", "http://blog.hatena.ne.jp/guide/pro", "http://warbler.hatenablog.com/archive", "http://warbler.hatenablog.com/entry/2017/12/02/235126", "http://warbler.hatenablog.com/entry/2017/11/06/113739", "http://warbler.hatenablog.com/entry/2017/09/06/223001", "http://warbler.hatenablog.com/archive/category/EM%E9%96%A2%E4%BF%82", "http://warbler.hatenablog.com/archive/category/%E7%92%B0%E5%A2%83%E5%95%8F%E9%A1%8C", "http://warbler.hatenablog.com/archive/category/%E7%A7%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E7%92%B0%E5%A2%83", "http://warbler.hatenablog.com/archive/category/%E7%A0%94%E7%A9%B6%E4%B8%8D%E6%AD%A3", "http://warbler.hatenablog.com/archive/category/%E8%AA%A4%E3%81%A3%E3%81%9F%E7%B5%B1%E8%A8%88", "http://warbler.hatenablog.com/archive/category/%E3%83%8B%E3%82%BB%E7%A7%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E6%94%BE%E5%B0%84%E7%B7%9A", "http://warbler.hatenablog.com/archive/category/%E3%83%9E%E3%82%B9%E3%82%B3%E3%83%9F", "http://warbler.hatenablog.com/archive/category/%E5%B2%A1%E5%B1%B1%E5%A4%A7%E4%BA%8B%E4%BB%B6", "http://warbler.hatenablog.com/archive/category/%E6%9B%B8%E8%A9%95", "http://warbler.hatenablog.com/archive/category/%E9%A3%9F%E5%93%81", "http://warbler.hatenablog.com/archive/category/%E5%81%A5%E5%BA%B7", "http://warbler.hatenablog.com/archive/category/%E3%83%9B%E3%83%A1%E3%82%AA%E3%83%91%E3%82%B7%E3%83%BC", "http://warbler.hatenablog.com/archive/category/%E6%8D%8F%E9%80%A0%E8%AB%96%E6%96%87", "http://warbler.hatenablog.com/archive/category/%E7%99%BA%E9%81%94%E9%9A%9C%E5%AE%B3", "http://warbler.hatenablog.com/archive/category/%E5%8C%BB%E7%99%82", "http://warbler.hatenablog.com/archive/category/%E9%9B%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E7%B5%B1%E8%A8%88", "http://warbler.hatenablog.com/archive/category/%E8%A6%AA%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E6%95%99%E8%82%B2", "http://blog.hatena.ne.jp/register?via=200227", "http://hatenablog.com/guide", "http://hatenablog.com/", "http://www.hatena.ne.jp/faq/report/blog?target_label=warbler&target_url=http%3A%2F%2Fblog.hatena.ne.jp%2Fgo%3Fblog%3Dhttp%253A%252F%252Fwarbler.hatenablog.com%252Fentry%252F2018%252F01%252F24%252F011739&location=http%3A%2F%2Fblog.hatena.ne.jp%2Fgo%3Fblog%3Dhttp%253A%252F%252Fwarbler.hatenablog.com%252Fentry%252F2018%252F01%252F24%252F011739"]

> meta.links.http
=> ["http://warbler.hatenablog.com/entry/2018/01/24/011739", "http://warbler.hatenablog.com/", "http://warbler.hatenablog.com/archive/2018/01/24", "https://www.emro.co.jp/information/04_HH/", "http://www.pref.aomori.lg.jp/kenminno-koe/24K23.html", "http://b.hatena.ne.jp/entry/http://warbler.hatenablog.com/entry/2018/01/24/011739", "https://twitter.com/share", "http://warbler.hatenablog.com/entry/2018/01/23/235522", "http://warbler.hatenablog.com/archive/2018/01/23", "http://warbler.hatenablog.com/entry/20150227/1425057866", "http://warbler.hatenablog.com/archive/2015/02/27", "http://warbler.hatenablog.com/archive/2013/09/03", "http://warbler.hatenablog.com/entry/20130903/1378217975", "http://warbler.hatenablog.com/entry/20130712/1373632961", "http://warbler.hatenablog.com/archive/2013/07/12", "http://warbler.hatenablog.com/entry/20130428/1367131822", "http://warbler.hatenablog.com/archive/2013/04/28", "http://warbler.hatenablog.com/about", "http://blog.hatena.ne.jp/guide/pro", "http://warbler.hatenablog.com/archive", "http://warbler.hatenablog.com/entry/2017/12/02/235126", "http://warbler.hatenablog.com/entry/2017/11/06/113739", "http://warbler.hatenablog.com/entry/2017/09/06/223001", "http://warbler.hatenablog.com/archive/category/EM%E9%96%A2%E4%BF%82", "http://warbler.hatenablog.com/archive/category/%E7%92%B0%E5%A2%83%E5%95%8F%E9%A1%8C", "http://warbler.hatenablog.com/archive/category/%E7%A7%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E7%92%B0%E5%A2%83", "http://warbler.hatenablog.com/archive/category/%E7%A0%94%E7%A9%B6%E4%B8%8D%E6%AD%A3", "http://warbler.hatenablog.com/archive/category/%E8%AA%A4%E3%81%A3%E3%81%9F%E7%B5%B1%E8%A8%88", "http://warbler.hatenablog.com/archive/category/%E3%83%8B%E3%82%BB%E7%A7%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E6%94%BE%E5%B0%84%E7%B7%9A", "http://warbler.hatenablog.com/archive/category/%E3%83%9E%E3%82%B9%E3%82%B3%E3%83%9F", "http://warbler.hatenablog.com/archive/category/%E5%B2%A1%E5%B1%B1%E5%A4%A7%E4%BA%8B%E4%BB%B6", "http://warbler.hatenablog.com/archive/category/%E6%9B%B8%E8%A9%95", "http://warbler.hatenablog.com/archive/category/%E9%A3%9F%E5%93%81", "http://warbler.hatenablog.com/archive/category/%E5%81%A5%E5%BA%B7", "http://warbler.hatenablog.com/archive/category/%E3%83%9B%E3%83%A1%E3%82%AA%E3%83%91%E3%82%B7%E3%83%BC", "http://warbler.hatenablog.com/archive/category/%E6%8D%8F%E9%80%A0%E8%AB%96%E6%96%87", "http://warbler.hatenablog.com/archive/category/%E7%99%BA%E9%81%94%E9%9A%9C%E5%AE%B3", "http://warbler.hatenablog.com/archive/category/%E5%8C%BB%E7%99%82", "http://warbler.hatenablog.com/archive/category/%E9%9B%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E7%B5%B1%E8%A8%88", "http://warbler.hatenablog.com/archive/category/%E8%A6%AA%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E6%95%99%E8%82%B2", "http://blog.hatena.ne.jp/register?via=200227", "http://hatenablog.com/guide", "http://hatenablog.com/", "http://www.hatena.ne.jp/faq/report/blog?target_label=warbler&target_url=http://blog.hatena.ne.jp/go?blog=http%253A%252F%252Fwarbler.hatenablog.com%252Fentry%252F2018%252F01%252F24%252F011739&location=http://blog.hatena.ne.jp/go?blog=http%253A%252F%252Fwarbler.hatenablog.com%252Fentry%252F2018%252F01%252F24%252F011739"]

> meta.links.internal
=> ["http://warbler.hatenablog.com/entry/2018/01/24/011739", "http://warbler.hatenablog.com/", "http://warbler.hatenablog.com/archive/2018/01/24", "http://warbler.hatenablog.com/entry/2018/01/23/235522", "http://warbler.hatenablog.com/archive/2018/01/23", "http://warbler.hatenablog.com/entry/20150227/1425057866", "http://warbler.hatenablog.com/archive/2015/02/27", "http://warbler.hatenablog.com/archive/2013/09/03", "http://warbler.hatenablog.com/entry/20130903/1378217975", "http://warbler.hatenablog.com/entry/20130712/1373632961", "http://warbler.hatenablog.com/archive/2013/07/12", "http://warbler.hatenablog.com/entry/20130428/1367131822", "http://warbler.hatenablog.com/archive/2013/04/28", "http://warbler.hatenablog.com/about", "http://warbler.hatenablog.com/archive", "http://warbler.hatenablog.com/entry/2017/12/02/235126", "http://warbler.hatenablog.com/entry/2017/11/06/113739", "http://warbler.hatenablog.com/entry/2017/09/06/223001", "http://warbler.hatenablog.com/archive/category/EM%E9%96%A2%E4%BF%82", "http://warbler.hatenablog.com/archive/category/%E7%92%B0%E5%A2%83%E5%95%8F%E9%A1%8C", "http://warbler.hatenablog.com/archive/category/%E7%A7%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E7%92%B0%E5%A2%83", "http://warbler.hatenablog.com/archive/category/%E7%A0%94%E7%A9%B6%E4%B8%8D%E6%AD%A3", "http://warbler.hatenablog.com/archive/category/%E8%AA%A4%E3%81%A3%E3%81%9F%E7%B5%B1%E8%A8%88", "http://warbler.hatenablog.com/archive/category/%E3%83%8B%E3%82%BB%E7%A7%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E6%94%BE%E5%B0%84%E7%B7%9A", "http://warbler.hatenablog.com/archive/category/%E3%83%9E%E3%82%B9%E3%82%B3%E3%83%9F", "http://warbler.hatenablog.com/archive/category/%E5%B2%A1%E5%B1%B1%E5%A4%A7%E4%BA%8B%E4%BB%B6", "http://warbler.hatenablog.com/archive/category/%E6%9B%B8%E8%A9%95", "http://warbler.hatenablog.com/archive/category/%E9%A3%9F%E5%93%81", "http://warbler.hatenablog.com/archive/category/%E5%81%A5%E5%BA%B7", "http://warbler.hatenablog.com/archive/category/%E3%83%9B%E3%83%A1%E3%82%AA%E3%83%91%E3%82%B7%E3%83%BC", "http://warbler.hatenablog.com/archive/category/%E6%8D%8F%E9%80%A0%E8%AB%96%E6%96%87", "http://warbler.hatenablog.com/archive/category/%E7%99%BA%E9%81%94%E9%9A%9C%E5%AE%B3", "http://warbler.hatenablog.com/archive/category/%E5%8C%BB%E7%99%82", "http://warbler.hatenablog.com/archive/category/%E9%9B%91%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E7%B5%B1%E8%A8%88", "http://warbler.hatenablog.com/archive/category/%E8%A6%AA%E5%AD%A6", "http://warbler.hatenablog.com/archive/category/%E6%95%99%E8%82%B2"] 

使い方はgithubにサンプルが乗ってますので、是非ご覧ください。

github.com

まとめ

何か困った時は先ずは調べてみることで、簡単に実装できるgemがいっぱいあるのでRubyは楽しいですね。

今日は、そんな感じです。

【Rails】NokogiriじゃなくてMechanize gemで簡単スクレイピング!

先日Nokogiriを使ったWebスクレイピング方法を紹介しましたが、もっと簡単に出来るgemを見つけたのでご紹介。

opiyotan.hatenablog.com

その名はMechanize

利用する準備

gemのインストール

gem 'mechanize'
$ bundle install

スクレイピング先のサイト情報を取得

今回も「はてなブログ」を使ってやってみたいと思います。

先ずは「はてなブログ」の情報を取得します。

class Mechanize
  url = "http://hatenablog.com/"

  agent = Mechanize.new
  page = agent.get(url)
end

使い方

titleを取得する

  puts page.search('title’)
$ rails runner lib/mechanize.rb

<title>Hatena Blog</title>

タグの中身になるテキストを取得する

  title = page.search('title')

  title.each do |ti|
    puts ti.inner_text
  end
$ rails runner lib/mechanize.rb

Hatena Blog

aタグのリンクurlを取得する

classを指定したい時は、.hogehogeのように指定すればok!

  entry_a = page.search('a.serviceTop-entry-img-a')
  entry_a.each do |a|
    puts a.get_attribute(:href)
  end
.
.
.
  # こうしてもやってることは、同じ
  entry_a = page.search('div.serviceTop-entry > a')
$ rails runner lib/mechanize.rb
Running via Spring preloader in process 18370
http://moognyk.hateblo.jp/entry/2018/01/23/080000
http://blog.jnito.com/entry/2018/01/23/075856
http://barzam154.hatenablog.com/entry/2018/01/22/205222
http://ibaya.hatenablog.com/entry/2018/01/23/111105
http://bandaicandy.hateblo.jp/entry/build22
http://www.netlorechase.net/entry/2018/01/22/080000
http://www.hinata-family.com/entry/2018/01/23/064657
http://www.bitco-salaryman.com/entry/2018/01/22/194205
http://zoweb.hatenablog.com/entry/2018/01/22/093904
http://www.beikokukabu.xyz/entry/02
http://hobby-diary.hatenablog.com/entry/2018/01/19/204839
http://www.daij1n.info/entry/2018/01/18/021528
http://www.lean-style.com/entry/fashionfortune
http://www.kandosaori.com/entry/2018/01/16/171030
http://www.black-gamer.com/entry/KITTE_pancake
https://www.hotpepper.jp/mesitsu/entry/kinniku/18-00007
http://osyobu-osyobu-3889.hatenadiary.jp/entry/the_shutter_is_released14
http://www.hoshinokiiro.com/entry/20180122/recipe/tukurioki-and-hotcook
http://www.megamouth.info/entry/2017/01/19/053801
https://srdk.rakuten.jp/entry/2017/01/19/110000
http://mistclast.hatenablog.com/entry/2017/01/22/110637

該当する情報を1件だけ取得したい場合は、atを使います。

  puts page.at('div.serviceTop-entry > a').get_attribute(:href)
$ rails runner lib/mechanize.rb
Running via Spring preloader in process 19231
http://blog.jnito.com/entry/2018/01/23/075856

aタグのテキストとリンクを全部取得する

  entry_a = page.links
  entry_a.each do |a|
    puts a.text
    puts a.href
  end
$ rails runner lib/mechanize.rb

http://hatenablog.com/
雪の日のユキヒョウ&オオカミ:東京が大雪だったので多摩動物公園に行ってきた
http://moognyk.hateblo.jp/entry/2018/01/23/080000
I AM A DOG
http://moognyk.hateblo.jp/entry/2018/01/23/080000
かねてより念願だった、雪の日の動物園に行ってきましたよ! 雪の動物園がずっと見たかった 雪の降る動物園はいつもと違う景色が観られて楽しいだろうな… と思…
http://moognyk.hateblo.jp/entry/2018/01/23/080000
・
・
・

現在のURLを取得する

agent.page.uri.to_s

descriptionを取得する

こちらが苦戦中。metainspectorというgemを使えば取得できることは分かったのですが、上と同じような感じで取得することが出来ない。

  puts page.at(':og:description’)
  puts page.at('meta[:og:description]’)
  puts page.at('meta[property=:og:description]')
  puts page.at('meta[property=":og:description"]')
  puts page.at('meta[name=":og:description"]')

うーん。全部ダメ。どうすればいいのか解決できず..

metainspectorというgemについては、また紹介します。

まとめ

簡単にスクレイピング出来ることが分かりました。

データさえ取得できてしまえば、後はどのように使うかだけなので色々面白いことが出来そうですね。

今日はこんな感じです。