pry-railsでRuby(Rails)を探索する話

pry-rails/binding.pry 使ってますかー

私。pry-railsが好きです。 めっちゃ使いやすい。 javascriptdebuggerも好きなんですが、それ以上に個人的にRails開発でのpryが好きなのでそれについて書こうと思っています。

はい というわけでMakeIT AdventCalendar 8日目pry-railsRuby(Rails app)を探索する話で投稿したいとおもいます。 前回ポエム書いちゃったので2回目は技術的な何かに触れないとねw 明日は @ymzk-jp がGitのHEADとは何者なのかを投稿してくれるはずです。

./bin/rails c とか binding.pry の話

個人的な話ですが、pry-rails。最初はすごい使いにくくてエラーに遭遇してから原因調査をして、 問題箇所を修正するみたいな開発をすることが多かったなと感じています。

ただ、pry(以下デバッガ)をある程度使えるといい感じにアプリ開発が進むなと感じました。 そのため、よく使うメソッドをまとめたいなと思います

Rails始めた人とかRails使ってるけどデバッガ使わない人に届いたら嬉しいですね。

今回モデルケースにするのは↓のようなものです。

1] pry(main)>
[2] pry(main)> show-models
   (1.5ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
ApplicationRecord
  Table doesn't exist

Comment
  id: integer
  user_id: integer
  post_id: integer
  body: string
  created_at: datetime
  updated_at: datetime
  belongs_to :post
  belongs_to :user
Post
  id: integer
  title: string
  body: text
  published: boolean # statusって名前にすれば良かったと後悔してます
  user_id: integer
  created_at: datetime
  updated_at: datetime
  belongs_to :user
User
  id: integer
  nickname: string
  email: string
  password_digest: string
  created_at: datetime
  updated_at: datetime
  has_many :comments
  has_many :posts

みたいなものを使ってた時。を想定して話していきたいなと思います。


rubyは全てがオブジェクト

突然ですがいわゆるclass,moduleなども一つのオブジェクトとなります。 オブジェクトであれば - 当然メソッド持っています - ほとんどの場合クラス本体もしくは、なにかのインスタンスであるでしょう。 - またそのクラスorインスタンスはほとんどの場合親クラスが存在しています といったことを念頭に起いた状態で次のコードを見てください

[1] pry(main)> self
=> main
[2] pry(main)> ls
ActiveSupport::ToJsonWithActiveSupportEncoder#methods: to_json
Rails::ConsoleMethods#methods: app  controller  helper  new_session  reload!
self.methods: inspect  to_s
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_

[3] pry(main)> cd app
[4] pry(#<ActionDispatch::Integration::Session>):1> self
=> #<ActionDispatch::Integration::Session:0x00007fd184305860
 @_mock_session=nil,
 @_routes=nil,
 @accept="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
 @app=
  #<SampleApp::Application:0x00007fd180ab8c28
   @_all_autoload_paths=

デバッガ起動直後のselfは main (オブジェクト?)を参照しています。(わからんw)

rubyの実行

ここ(デバッガ)ではirb同様Rubyを実行することができます

Ex) fizzbuzz

[42] pry(main)> 100.times{|n| puts n % 15 == 0 ? 'fizzbuzz' : n % 5 == 0 ? 'fizz' : n % 3 == 0 ? 'buzz' : n }

Railsでの使い方

Rubyの使い方はあまり触れずに今回はRailsの使い方を。 先ほど cdをしましたが。 bash使ってれば察すると思いますが、 lsもありそうですよね。

[47] pry(main)> self
=> main
[48] pry(main)> ls
ActiveSupport::ToJsonWithActiveSupportEncoder#methods: to_json
Rails::ConsoleMethods#methods: app  controller  helper  new_session  reload!
self.methods: inspect  to_s
instance variables: @app_integration_instance  @controller
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_
[49] pry(main)>

cd, ls

ここでいうlsは’self’のオブジェクトがもっている(利用可能な)メソッドを羅列してくれます。

例えば今回のモデルである'Post'クラスや’Post’のインスタンスに潜ってlsをしてみようと思います

[70] pry(main):1> cd Post
[85] pry(Post):2> self
=> Post(id: integer, title: string, body: text, published: boolean, user_id: integer, created_at: datetime, updated_at: datetime)

こうするとPostクラスに移動した状態です 基本的に、今いる参照先(currentなオブジェクト?)を確認する際は'self'を使う、もしくは'プロンプト'の表示項目 "[82] pry(Post)"を確認する などをすると思います

[82] pry(Post):2> ls
Object.methods: yaml_tag
ActiveModel::Naming#methods: model_name
ActiveSupport::Benchmarkable#methods: benchmark
ActiveSupport::DescendantsTracker#methods: descendants  direct_descendants
ActiveRecord::ConnectionHandling#methods:
  clear_active_connections!  clear_reloadable_connections!  connection_config              connection_specification_name=  mysql2_connection
  clear_all_connections!     connected?                     connection_pool                establish_connection            remove_connection
  clear_cache!               connection                     connection_specification_name  flush_idle_connections!         retrieve_connection
ActiveRecord::QueryCache::ClassMethods#methods: cache  uncached
ActiveRecord::Querying#methods:
  any?          distinct     find_each
  #--------省略-----------------
  Post.methods: __callbacks  _reflections  _validators  attribute_type_decorations  defined_enums  draft  published  publisheds
Post#methods: autosave_associated_records_for_user  belongs_to_counter_cache_after_update
...etc

例えば、モデルクラスであるPost、ここで'ls'をするとRailsのモデルが持ってるメソッドが全て表示されます。 破線の後半にある Post.methodsの部分はPostクラスにて定義したものが表示されます さらに、自身の定義したメソッドを見る場合はいくつか方法があります

  • object#methods.grep() #-> tab押すと予測がでる
  • object#find-method #-> Recursively search for a method within a Class/Module or the current namespace.
  • ls --grep #-> Show the list of vars and methods in the current scope., # Exclude -q, -v and --grep because they,

だそうです。 使ってる感じはこちら

おすすめは メソッド名がある程度わかってるのであれば、ls --grepを使う。 そうでないのであれば methods.grep(:hog) -> hogを含んでるメソッドをタブで予測表示される という使い分けです。

appオブジェクト

デバッガーではappオブジェクトなるものにアクセスすることができます appオブジェクトを経由することでURLヘルパー、pathヘルパー、またリクエストを送ることが可能です URLhelperといえば $./bin/rake routesを使う人やhttp://localhost:3000/rails/info/routesを使う人は多いのではないでしょうか?

これらの確認はこのデバッガでも可能です

[138] pry(main)> show-routes
                   Prefix Verb   URI Pattern                                                                              Controller#Action
                    users GET    /users(.:format)                                                                         users#index
                          POST   /users(.:format)                                                                         users#create
                 new_user GET    /users/new(.:format)                                                                     users#new
                edit_user GET    /users/:id/edit(.:format)                                                                users#edit
                     user GET    /users/:id(.:format)                                                                     users#show
                          PATCH  /users/:id(.:format)                                                                     users#update
                          PUT    /users/:id(.:format)                                                                     users#update
                          DELETE /users/:id(.:format)                                                                     users#destroy
                    posts GET    /posts(.:format)                                                                         posts#index
                          POST   /posts(.:format)                                                                         posts#create
                 new_post GET    /posts/new(.:format)                                                                     posts#new
                edit_post GET    /posts/:id/edit(.:format)

またこのRoutingコマンドに関しても先の'ls'で確認したようにGrepを使えます

[144] pry(main)> show-routes --grep post
                    posts GET    /posts(.:format)                                                                         posts#index
                          POST   /posts(.:format)                                                                         posts#create
                 new_post GET    /posts/new(.:format)                                                                     posts#new
                edit_post GET    /posts/:id/edit(.:format)

そのほかにも。RouteをControllerごとに見るのであれば

[39] pry(main)> find-route Post
Routes for PostsController
--
index GET /posts(.:format)  [posts]
create POST /posts(.:format)
new GET /posts/new(.:format)  [new_post]
edit GET /posts/:id/edit(.:format)  [edit_post]
show GET /posts/:id(.:format)  [post]
update PATCH /posts/:id(.:format)
update PUT /posts/:id(.:format)
destroy DELETE /posts/:id(.:format)

というわけで、実際に調べた posts_path, new_post_pathなどの確認や、リクエストをしてみたいと思います。

[161] pry(main)> app.posts_path
=> "/posts"
[162] pry(main)> app.new_post_path
=> "/posts/new"
[163] pry(main)> app.post_path(1)
=> "/posts/1"
# このように生成されたRouteの確認ができますね。
# 実際にpost_pathにreqしてみると
[177] pry(main)> app.get app.posts_path
Started GET "/posts" for 127.0.0.1 at 2018-12-08 20:02:01 +0900
   (0.9ms)  SELECT `schema_migrations`.`version` FROM `schema_migrations` ORDER BY `schema_migrations`.`version` ASC
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.3ms)  SELECT `posts`.* FROM `posts`
  Rendered posts/index.html.erb within layouts/application (206.8ms)
Completed 200 OK in 533ms (Views: 503.4ms | ActiveRecord: 2.7ms)

=> 200
[200] pry(main)> res = app.response
# res.bodyとするとSSRされたHTMLが見れます

[227] pry(main)> app.request.params
=> {"controller"=>"posts", "action"=>"index"}
[228] pry(main)> app.request.headers
=> header情報
[229] pry(main)> app.controller.class
=> PostsController

といったようなリクエストを送信することもできます。

helperオブジェクト

railsで開発してるとメソッドの切り出しなどにHelperを使うことがあると思います。 そういったときのHelperもデバッガーにて確認することが可能です。

module ApplicationHelper
  def hello_world
    puts 'hello world'
  end
end

例えばこんな感じのHelperがあると

[4] pry(main)> helper.hello_world
hello world
=> nil

このように呼ぶことが可能です。 他にも今まで同様

[21] pry(main)> cd ApplicationHelper
[22] pry(ApplicationHelper):1> self
=> ApplicationHelper
[23] pry(ApplicationHelper):1> ls
ApplicationHelper#methods: hello_world
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_
[24] pry(ApplicationHelper):1> show-method hello_world

From: /Users/fumihumi/project/sample_app/app/helpers/application_helper.rb @ line 2:
Owner: ApplicationHelper
Visibility: public
Number of lines: 3

def hello_world
  puts 'hello world'
end

という形で参照することができます ここでHelperメソッドを呼び出したい場合は

[38] pry(ApplicationHelper):1> show-source self

From: /Users/fumihumi/project/sample_app/app/helpers/application_helper.rb @ line 1:
Module name: ApplicationHelper
Number of lines: 9

module ApplicationHelper
  def hello_world
    puts 'hello world'
  end

  def self.public_world
    puts 'class method hello'
  end
end
[39] pry(ApplicationHelper):1> public_world
class method hello
=> nil
[40] pry(ApplicationHelper):1> hello_world
NameError: undefined local variable or method `hello_world' for ApplicationHelper:Module
from (pry):14:in `__binding__'

一時的にクラスメソッドにする。、もしくは mainを参照している状態でhelper.hello_worldとします。

show-method(show-source)

これはメソッドの定義を見ることができます たとえばshow-routesをみてみると

[64] pry(main)> show-source show-routes

From: /Users/fumihumi/project/sample_app/vendor/bundle/gems/pry-rails-0.3.8/lib/pry-rails/commands/show_routes.rb
Number of lines: 76

class PryRails::ShowRoutes < Pry::ClassCommand
  match 'show-routes'
  group 'Rails'
  description 'Show all routes in match order.'
  banner <<-BANNER
    Usage: show-routes [-G]
    show-routes displays the current Rails app's routes.
  BANNER

  def options(opt)
    opt.on :G, "grep", "Filter output by regular expression",
           :argument => true,
           :as => Array
  end
  ...etc

のようになっており、DescとOptionの存在を知ることができますね。 他にも自分が定義しているメソッドなども参照ができます。

edit

これは引数に渡したメソッドがVimで(?)起動がされます。 多分'.pryrc'で設定できるはず GIFにしましたがまぁこんな感じでみれるということです。

reload

editorなどでアプリのモデル等を編集したらreload!をすることでアプリを再読み込みすることができます。 ただ、時々意図しない感じな挙動になることがある?気がするのでおかしくなったら'exit'した方がいいかと思います。

watch

4] pry(main)> hoge = 'hoge'
=> "hoge"
[15] pry(main)> fuga = 'fuga'
=> "fuga"
[16] pry(main)> watch hoge
Watching hoge
watch: hoge => "hoge"
[17] pry(main)> watch fuga
Watching fuga
watch: fuga => "fuga"
[18] pry(main)> hoge = 'ww'
watch: hoge => "ww"
=> "ww"
[20] pry(main)> foo ='foo'
=> "foo"
[21] pry(main)> foo << 'ee'
=> "fooee"
[23] pry(main)> fuga << 'ee'
watch: fuga => "fugaee"
=> "fugaee"

watchを使うとWatchで指定した変数が変更があったときにwatch: <before> => <after>で教えてくれます

hist

名前の通りHistoryをみせてくれます。 これもGrepができます

[48] pry(main)> hist --grep find
20: show-method find-route
21: find-route Post
23: find-route Post

便利。w

ActiveRecord

user = User.last
user.posts.published.to_sql
=> "SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 10 AND `posts`.`published` = 1"
# to_sqlメソッドでこれから吐かれるSQLをみれる

[100] pry(main)> (Date.today..Date.tomorrow).to_s(:db)
=> "BETWEEN '2018-12-08' AND '2018-12-09'"
# 引用:http://thr3a.hatenablog.com/entry/20181206/1544099172

[106] pry(main)> user.posts.published.new
=> #<Post:0x00007fd184778208 id: nil, title: nil, body: nil, published: "published", user_id: 10, created_at: nil, updated_at: nil>
# user.posts.new -> user_id == user.id
# user.posts.publisdhed.new -> published: publishedな状態でnewできる

ActiveRecord周りの便利な使い方はSQLを考えながら書くといい感じに描けそうですね わたしはまだまだダメなのでもっと頑張りたいところの一つです。

model, DB構造

[92] pry(main)> show-model User
User
  id: integer
  nickname: string
  email: string
  password_digest: string
  created_at: datetime
  updated_at: datetime
  has_many :comments
  has_many :posts

のようにするとモデルのColumnなどを把握することができます

shell-mode

[130] pry(main)> shell-mode
pry main:/Users/fumihumi/project/sample_app $

と、なんかプロンプトが変わりますが操作が変わる感じはあまりしてません。 どうやって使うのか知ってたら教えていただきたいです...

つらつらと書いてきましたがこんな感じでデバッガー一つとっても複雑なことがたくさんできます。 こういった使い方もあくまでも一つの使い方だと思いますし、もっと便利な方法があるのかもしれません。 自分のデバッガーの使い方を見つけておくとよりよいプログラミングになるのかなとか思ったりしています。 もっと自由自在に使いこなせるようになりたいですね。

以上でAdventCalendar8日目を終わりにしたいと思います。最後まで読んでいただきありがとうございます。 メモ書きのような文章になってしまい申し訳ありませんw

私がLintを愛する3つの理由

Lint好きですか???

普段はRubyJavaScriptを利用しているfumihumiです。 最近はTypeScriptが楽しくなってきました。

突然ですが、 私はLintが好きです。 初めてLintを導入する時ってちょっとしたルールについて揉めたりしませんか????(した) リアル(現実)の揉め事なんかちっちゃく感じるくらいLintからもらえる恩恵って大きいと思っています。

はい。

というわけで MakeIT AdventCalendar 2日目は技術ポエムで投稿したいとおもいます。 明日は @wh1tecat が投稿してくれるはz...

ところでこのカレンダー5日分ほど空いてしまっている様ですね。 きっといい記事を納めてくれる人がいることを僕は信じたいとおもいます... :thinking: せっかくなので全日程埋めたい!!!!!!!!!

まぁ余談はこの程度にして、

lintを導入することで得られる恩恵とその効能について考えてみたいなと。

と、いうのもLintって基本的にカッチカチに設定した方がいいと考えてる私の設定ファイルでCIを回していると学校でLintを使ってる時に

tslintで怒られた件 eslint硬い件

のような意見をもらったので改めて考えてみたいなと思って考えていたことをあらためてまとめていきたいとおもいました

ところで皆さんはLintのルールってどの程度の粒度で設定していますか?????

例えば、JavaScriptなら

const bool = true;

// ver 1
if(bool){return;}
// ver 2
if (bool) {return;}
// ver 3
if (bool) { return; }

のように if一つとっても↑みたいにかけますよね?????? これらのルールってどうやって決めてますか??????

他にも疑問になりがちな

  • 文末セミコロン
  • ブレース前後のスペース
  • 同じく丸括弧前後のスペース
  • 文章のシングル(ダブル)クォーテーション

これらのルールって決めた方がいいのでしょうか?

先に自分の結論から言うとルールは硬い方が良いんじゃないでしょうか?????

ルールを決める

細かいルールはルールを考える人、Lintを導入する人、もしくはチームで相談すると思いますが、例えば

  • クォーテーションに関して であれば私は '式展開が不可能な方' && 'US配列で打ちやすい'という理由からシングルクォーテションを採用しています。
  • インデントはスペースを使ったりとしています。

ただ、こういった細かいルールに関しては開発者およびコーディング担当者は気にする必要ってないと私は思っています。 とは言ってもコード書くときに意識しないと怒られが発生しますよね?w

ただ、そういった怒られ案件(ストレス)っていい感じに回避できそうだとは思いませんか? そうです。 EditorConfig や エディターの拡張機能たちを使えばそういったことが可能です。 私はVSCodeを利用していますが、tslint, stylelint,prettierの様な拡張機能、editorConfigといったものも導入することでストレスが少なく開発に専念することに成功しています。

これらは保存時にいい感じに整形する様な設定を加えることができる(もしかしたら他の拡張機能かも)のでコードを書く際はほとんどストレスがなく開発することができます。 また細かいLintのバグはCLIから tslint **.ts --fixの様にすることでAutoCollectができますね(めっちゃ便利

なので今回はこういった細かいルールについてではなくその他のルールについて考えていきたいなと思っています。 基本的な設定はeslint:allもしくはeslint:recommended これのどちらかを採用し、そこから好みに応じてルールを緩和するのが良いと思っています。

...本題からそれてしまいましたが、

私がLintを好む3つの理由について話したいと思います。

  • 自身のコーディングを規制することができる
  • チームとしてコードに統一感を持たせることができる
  • 潜在的なエラー(バグ)を潰すことができる

Lintの導入にはこの様な3つのメリットがあると思っています。

それぞれについて掘っていくと。

自身のコーディングを規制することができる

これは

  • 独学で学んでいる人
  • いろいろな言語に触れていてその言語特有の書き方に慣れていない人
  • レビューされる機会がなく各々のコーディングになってしまう人

といった人に対して抜群の効果を発揮します。

自分がそうなのですが、プログラミング初めてまもない頃はすごい適当にコードを書いてしまい、可読性が抜群に悪かったり、動くプログラムを雑に書いてしまったり、という様なことが起きていました。

こういった

  • 可読性が悪い
  • とりあえず動くコード(汚い処理)
  • 言語特有の書き方でなくぱっと見読みづらい

という事象をLintの活用で避けることができます。

ね?Lint便利でしょ?

チームとしてコードに統一感を持たせることができる

複数人で開発を始めると当然の様に人それぞれの好み(インデント・ブレース・カンマ)などで宗教戦争が発生しますよね。(?しますよね)

こういったものを前述した

  • EditorConfig
  • Linter
  • Editor設定(Extension)

を活用することでいい感じにすることができます

おすすめはVScodeとLint,EditorConfigの活用です。気になる方はググってください。

ね?Lint便利でしょ?

潜在的なエラー(バグ)を潰すことができる

Lintを活用することで潜在的なエラーを消すことができます。 未宣言の変数の利用や、本来もってないメソッドを使った時に怒られたり、といったことがLintによってできます。 (これがかなり便利なわけですがいい例えが思い浮かびませんでしたw。)

と、いうわけでいい感じにコードを書くために硬いLintと一緒に生活するのはいかがですか??? (雑すぎるまとめ方)

ね?Lint便利でしょ?

番外編:lintをCIと活用する

LintはCircleCIやTravisCIのようなCIツールと一緒に使うとよりよい Lint人生を歩けます

CIツールの設定はいい感じに調べてみれば出てくると思います。

その中でも私のオススメは他人のGitHubからパクることですね。 選択肢としては、 1. 知り合いのGitHubのRepoを漁る。GitHubの検索を活用する。 2. もしくはググって導入事例と設定ファイルを見つける。

などなどをすると良いと思います。

私もそうでしたが、CircleCIの設定は最初は難しく感じがちですが、 他人の設定を真似するとかなり楽に設定することができます。 毎回手元のTerminal(CMD)でLintの実行することもできますが、GitHubなどにPushした際を発火材にしてLintを実行することができます。 またCIツール使うことのメリットはLintだけでなくテストの実行などもテスト環境から行うこともできる様になりますよね。 初めてのCIでテストは難しいかもしれませんがテストも楽しいので明日から!楽しいCI人生を歩きましょう?!

ね?Lint便利でしょ?

まだLint入れてない人は 新規ISSUEに Lint入れたい てやってみてはいかがでしょうか???? きっと考えている人が他にもいるはずです。 良いLintライフを!


さてお粗末な文章となってしまいましたが MakeIT AdventCalendar 2日目は@fumihumiが担当しました。

この記事をみてLintを好きになってもらえたら嬉しいですねw 明日もMakeIT AdventCalendarを楽しみにしていてください!

rails のサーバー立ち上げようとしたらセグフォした件

Railsでセグフォした

teratail.com

rails s ができません。mysql2-0.5.1/lib/mysql2/client.rb:90: [BUG] Segmentationエラー

いやいや、RailsSegmentation Faultってそんなわけないでしょ??????????

お。??まじやんwwwwwwwwwwwそんなことある????wwwwwwwって感じでした

以下質問文引用

開発中に突然warning: already initialized constant FileUtils::RUBYエラーが出てしまい、ruby、railsを再インストールしました。

そうしたところSegmentation fault at 0x00000000000000と出てしまっています。

どうもmysqlとの紐付けがうまく行ってないのかと思いますが、原因不明です。

rails sをしてもサーバーを起動させることができないでいます。 

どなたかご助言をいただけますと幸いです。

ふむふむ。よくわからんがエラー前に何かしたんじゃないの????という感じですねw ただ話を聞いていると特に何もしていないっぽかったのでよくわからんという感じです。w

...エラー文

vendor/bundle/ruby/2.4.0/gems/mysql2-0.5.1/lib/mysql2/client.rb:90: [BUG] Segmentation fault at 0x00000000000000
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]

-- Crash Report log information --------------------------------------------
   See Crash Report log file under the one of following:                    
     * ~/Library/Logs/DiagnosticReports                                     
     * /Library/Logs/DiagnosticReports                                      
   for more details.                                                        
Don't forget to include the above Crash Report log file in bug reports.     

-- Control frame information -----------------------------------------------
c:0043 p:---- s:0315 e:000314 CFUNC  :connect
c:0042 p:0688 s:0303 e:000302 METHOD /Users/___/Desktop/lance_note/vendor/bundle/ruby/2.4.0/gems/mysql2-0.5.1/lib/mysql2/client.rb:90 [FINISH]
c:0041 p:---- s:0289 e:000288 CFUNC  :new

ほぉ?なんかgemsの下のmysql2の中のファイルで死んでるっぽいですね?。 とはいえ直前まで動いてたらしいし動くでしょ、普通w

たまたま該当の質問者と知り合いだったので連絡をしつつ解決した経緯について触れたいと思います。

なんとなく現状のMysqlRailsの疎通を確認したかったので

$ rails s
$ rails c
$ rials db:console
$ rails db:migrate:status

などのRailsコマンドを叩いてもらうと rails cだけがうまく通るみたいです。 Rails本体はうまく動いてるっぽいですね。RailsとDBを繋げようとすると◯ぬ。

$ mysql -u root;
$ show databases;
$ use sample_db;
$ show tables;

のようなMysql自体へのアクセスやSelectクエリなどは問題なく動くみたいです。

RailsMysql繋げようとするとセグフォする?????????!w

この時mysql2のgemのバージョンの問題かと思って

0.5.1
0.5.2

などに変えたりしてもエラーが発生してました。

fumihumi.hatenablog.com

などを試してみたりしてもらっても変わらん。 なるほどよくわかrん

結論

...mysql2のGemのVersionもう一個下げてみますか?と思い。 0.4.10 に下げてみてもらったところ、解決されたようです。

うーん謎いですね。特にISSUEなどになってるわけでもないので特定の環境下にて再現されるものなのかもしれません。 ただ、 rails puma segmentation fault ってググってもあんまりヒットしなかったのでとりあえず書いてみました。

何かわかる人いたら教えてください。

iOSシミュレータで開発効率が100倍増しになった話

TL;DR

Web開発するのに、スマホ画面での検証しないと行けないじゃないですか。 いままで chrome, Chrome Canary, safari, secretWindowとかを駆使して iphone5, 7, 7plus, Xのサイズ試してたのですが、◯ぬほどめんどくさいなぁと感じてしまったんですよね。(遅い) それを解決しようってのが今回の話です。

きっかけは↑の記事でのシミュレータをフルウインドウでひらくというもの。 ↑の状態で シミュレータ複数横並び にできたら幸せじゃないですか!

という訳でやってみました!

やったこと。

https://github.com/facebook/FBSimulatorControl

今回は使ったのは FBSimulatorControlというFacebook社が提供してるOSS。 このOSSbrew を使って入れてました。

  $ brew tap facebook/fb
  $ brew install fbsimctl --HEAD

$ fbsimctl list fbsimctlコマンドにlistを渡すと起動可能なシミュレータの一覧を取得できるみたいです。

@fumihumi:fbsimctl list | grep iPhone
022068FE-C8EB-4B70-A248-59050F47DEBB | iPhone X | Booted | iPhone X | iOS 11.4 | x86_64
B4D8BDFD-0F86-411A-986F-524C3B646547 | iPhone SE | Shutdown | iPhone SE | iOS 11.4 | x86_64
5E5E1123-AEF2-4765-90AA-B6C82ED55ABF | iPhone 8 Plus | Shutdown | iPhone 8 Plus | iOS 11.4 | x86_64
BDC8695E-568C-454E-9DD8-8732677B7A9D | iPhone 8 | Shutdown | iPhone 8 | iOS 11.4 | x86_64
CA9F509D-A76B-4708-B7B1-07341D8FC324 | iPhone 7 Plus | Shutdown | iPhone 7 Plus | iOS 11.4 | x86_64
DA208130-4BED-433B-89CB-BA35C0CBC5A9 | iPhone 7 | Shutdown | iPhone 7 | iOS 11.4 | x86_64
EB6362A3-BBA7-45DD-95AF-2AFA91AAD624 | iPhone 6s Plus | Shutdown | iPhone 6s Plus | iOS 11.4 | x86_64
2DE031F8-DCDB-4CD2-91B1-C8915F3E3644 | iPhone 6s | Shutdown | iPhone 6s | iOS 11.4 | x86_64
2EBD9CF9-1654-4E18-8017-53A2901F9CC9 | iPhone 6 Plus | Shutdown | iPhone 6 Plus | iOS 11.4 | x86_64
D6F59370-3C52-4DC0-823C-85B5D20E222A | iPhone 6 | Shutdown | iPhone 6 | iOS 11.4 | x86_64
DD24F91C-A6BF-470D-B8A9-B288A8D215CC | iPhone 5s | Shutdown | iPhone 5s | iOS 11.4 | x86_64
UUID:(識別子的な何かっぽい)
機種:(AppleTV, iPad Pro, iPhone, AppleWatch)など
起動状態:(Shutdown | booted)

などが乗ってますね

まぁ

fbsimctl list | grep -e 'iPhone X' -e 'iPhone SE' とかでグレップした上でそのUUIDを元に

fbsimctl B4D8BDFD-0F86-411A-986F-524C3B646547 2DE031F8-DCDB-4CD2-91B1-C8915F3E3644 boot

のように fbsimctl UUID boot とすることで複数の端末をエミュレートできます。

結局なにしてたの?

Web開発で複数のユーザで確認したいとき。 ブラウザでタブ開いて確認してもいいんですが、シークレットウインドウつかったりChrome, safari, firefoxで別ユーザでログインしたり、大変。。。。。

そんな時にiPhoneシミュレータでできると便利なんですよね。

詰まったこと

$ brew install fbsimctl --HEAD がうまくいかなかった

org.carthage.CarthageKit/dependencies/GCDWebServer: Operation not permitted

というエラーが出ていた、

sudoつけて、Installしようとしたんですが、 sudo brew install 〇〇 ってダメなんですね。初めて知りましたw

↑のエラーは Carthage を消せば良さそうみたいです。

$ brew uninstall --force carthage
$ rm -rf ~/Library/Caches/org.carthage.CarthageKit

特に Carthage に思い入れないので容赦なく消してやりました。 まぁ大丈夫っしょw。 iOSエンジニアは少し躊躇したりするんですかね? よくわかりませんけど 頑張ってください。。w

まとめ

iOSシミュレータを使ってスマホレイアウトの確認をすると、想像以上にやりやすい! (最近ChromeのDeveloperToolがより便利になってなんとも言えない気持ちになってる)

gitのssh_key作ったのにssh -T で permission deniedされた。

SSHKeyを追加したかったんですけど

qiita.com

↑の言われるようにやってました 

  ssh-keygen -t rsa -b 4096 -C  '#{めあど}@#{こめんと}'
  pbcopy  < github_id_rsa.pub
  # ブラウザでGithubのSSH登録

疎通確認をする↓

$ ssh -T git@github.com
git@github.com: Permission denied (publickey).

# なにやらうまくいかないけどとりあえず管理者権限でやったろ

$ sudo ssh -T git@github.com
Password:
The authenticity of host 'github.com (192.30.255.112)' can't be established.
RSA key fingerprint is SHA256:nThbg~~~~~~~~~~E5SY8.
Are you sure you want to continue connecting (yes/no)?
Host key verification failed.

うーん。うまくいかない。 sshの鍵は作ってるんだけど手元のpcでちゃんと認識できてないっぽい?

$ ssh-add -K ~/.ssh/github_id_rsa
Enter passphrase for /Users/{ユーザー名}/.ssh/github_id_rsa:
Identity added: /Users/{ユーザー名}/.ssh/github_id_rsa

ってやったらできました。

ssh-addの-Kはなくても問題ないんですがpc再起動すると読み込みに失敗したりするのでオプションつけたほうがよさそう

うーん。よくわからん

railsで検索するならRansack!!!!!!!!!!!!

ransack を使ったときになぜか検索できなかった話

最近の悩みだったんですよ ()

Railsの検索フォームを作る時ってさりげなくめんどくさくないですか。

めんどくさいですよね;;... めんd .... ゲホゲホ (異論は認める)

+ = form_tag xxx_yyyy_search_path do
+   .row
+     .form-group.col-sm-2
+       = text_field_tag :xxx_name,
+       { placeholder: "xxx", class: "form-control input-sm" }
+     .form-group.col-sm-2
+       = text_field_tag :yyy_name,
+       { placeholder: "yyy", class: "form-control input-sm" }
+      .form-group.col-sm-2
+        = submit_tag '検索するよー', class: 'btn btn-default btn-sm'
+def search 
+  @samples = Sample.page(params[:page]).per(PER)
+  if params[:xxx_name].present?
+    @sample = @sample.joins(zzz: :xxx)
+                     .where('xxx.name like ?', "%#{params[:xxx_name]}%")
+  end
+
+  if params[:yyy_name].present?
+    @sample = @sample.where('name like ?', "%#{params[:name]}%") 
+  end
+  
+  @sample = @sample.decorate
+end

これ。死ぬほど冗長だし、ちょっと(どころじゃなく)見栄えが悪いんですよね。 検索したいcolumnがふえるたびにViewに

+ .form-group.col-sm-2
+   = text_field_tag :new_column,
+   { placeholder: "検索したいcolumnふえたよ!", class: "form-control input-sm" }

↑のようなViewを追加し、

+  if params[:new_column].present?
+    @sample = @sample.where('new_column like ?', "%#{params[:new_column]}%") 
+  end

のように追加しないといけないんですよ。 DBがふくらんで3個どころじゃなく検索したくなったらどうするつもりですか?????? (心の声:頑張る) ←やめてください

そんな時に使うのが Ransack というGemです (https://github.com/activerecord-hackery/ransack

これがとても素晴らしいもので、早い、すごい、便利の三拍子を揃えているのです!

と、いうわけで

ransackの紹介と導入について

簡単に...(きになる方は本家みてw)

ransackは...README.

Ransack enables the creation of both simple and advanced search forms for your Ruby on Rails application (demo source code here). 
If you're looking for something that simplifies query generation at the model or controller layer,
you're probably not looking for Ransack (or MetaSearch, for that matter). Try Squeel instead.

だそうです。まあつまり シンプルだけど高度な検索をしたいならコレ!というわけです。 (雑)

ransackを使うためには

gem 'ransack'

もしくは

gem 'ransack', github: 'activerecord-hackery/ransack' # if you would like to use lates updates, use the master branch

をGemfileに記載し $ bundleするだけでじゅんびは終わりです。

def index
  @q = Person.ransack(params[:q])
  @people = @q.result(distinct: true)
end
<%= search_form_for @q do |f| %>

  # Search if the name field contains...
  <%= f.label :name_cont %>
  <%= f.search_field :name_cont %>

  # Search if an associated articles.title starts with...
  <%= f.label :articles_title_start %>
  <%= f.search_field :articles_title_start %>

  # Attributes may be chained. Search multiple attributes for one value...
  <%= f.label :name_or_description_or_email_or_articles_title_cont %>
  <%= f.search_field :name_or_description_or_email_or_articles_title_cont %>

  <%= f.submit %>
<% end %>

とすれば良いみたいです。個人プロジェクトに入れたのだいぶ昔でサンプルないので公式をコピペ。

search_form_for

というのがRansackが提供しているメソッドでRansackを使う検索をする場合はForm_forではなくこれを利用します。
  上記のような記載にしてあげることでRansack様の恩恵を受けられます。   またransackを利用するさいにはsearch_filedへ引数を利用することで検索条件を変更することが可能です。

上記のような、

<%= f.search_field :name_cont %>
<%= f.search_field :articles_title_start %>

という場合は name columnに対してLike検索、 関連先の、articlesのtitleに対してのlike検索。を行います。 (多分 has_many articlesの関係)

  その他にも、https://github.com/activerecord-hackery/ransack

シンボル引数 内部条件
column_eq 完全一致
column_matches like検索
column_cont 部分一致
column_true bool検索
column_blank blankかどうか
column_present 存在確認
column_null null確認
not column_not_eq みたいに否定ができる

などなどあります。 自分は公式のドキュメントや、

http://nekorails.hatenablog.com/entry/2017/05/31/173925

↑のサイトをみたりしてます。


そんな便利なRansackさんですが、

セキュリティ的なことを考えると機能によってはチューニングしないといけないのです。

今回自分はそれに気づくまで時間をとかしてしまったので、猛省しながら本記事を書こうと思ったわけです。

ちなみに今回僕が遭遇したのは、

特定のcolumnでは検索できるのに 他のcolumnでは検索ができない。

まずは遭遇したエラー文ですが↓

 undefined method `xxx_cont' for Ransack::Search<class: Entry, base: Grouping <combinator: and>>:Ransack::Search

うーん、エラー文としてはよくあるアレですよね、
Nomethod error ........ ウルセェ!モデルに columnあるだろ!!!! f●ck!!!!!!!!!!

ただ、この時もControllerにて

def action
  @q = Model.search(params[:q])
  @instance_valiables = @q.result
end

のようにしてたわけで、この @q の内容は

=> Ransack::Search<class: Model, base: Grouping <combinator: and>>

になっており、正常にRansackのメソッドになってるんですよね。うーん。

RailsContsoleで

Model.ransack({xxx_cont: 'sample'}).result

→と、すれば該当モデルの'xxx'カラムに対して検索もしてくれてる風なレスポンスですしお寿司。。。 (今思えば、実際は検索されていないで Model.allの結果になってたっぽい気がする)

↑↑↑↑↑↑

とまぁ。状況の創造はできたと思うので実際の対処になります。

該当columnで検索してないのに絞り込めてない時の対処が以下になります。

問題としては該当モデルのファイルにて

self.ransackable_attributes self.ransackable_associations

ransackのオーヴァーライドが原因になっていました。 自分が作業をしていた時は

  def self.ransackable_attributes(*)
    %w[created_at]
  end

  def self.ransackable_associations(*)
    %w[]
  end

となっており、検索したい name columnが検索対象の columnとして登録がされておらず。 また、関連先の定義がされていなかったため、articleに対する検索すらもできなかったということになります。。。。。。。。。。。。。。。。。。

つらい。 しんどぃ。。

なので、以下のメソッドに変更を加え、

  def self.ransackable_attributes(*)
    %w[created_at name]
  end

  def self.ransackable_associations(*)
    %w[articles]
  end

のようにすると name columnでも検索が可能になりますし、articleへの探索も可能になるのです。

これで動くのでひとあんしんですね。

余談

まぁなんというか、エラーでて調べてもこの手のエラーへの対処がなかったので今回書いてみたんですが。 行ってしまえば、自明な内容になってしまいそうなので、今回はさらに一歩踏み込んだ内容について考えてみようかなと。

ransackのsource codeをのぞいてみよう。。。!

初めてOSS?をコード見るためにCloneしました。
はるか昔にDevise(認証用のGem)をみたことがあるが黒魔術すぎて3秒で諦めたなぁと物思いに老けながらgit clonne...)

今回の諸悪の根源である該当メソッドは以下のファイルにて定義されています。 (https://github.com/activerecord-hackery/ransack/blob/master/lib/ransack/adapters/active_record/base.rb)

 # Ransackable_attributes, by default, returns all column names
 # and any defined ransackers as an array of strings.
 # For overriding with a whitelist array of strings.
 #
 def ransackable_attributes(auth_object = nil)
    @ransackable_attributes ||= if Ransack::SUPPORTS_ATTRIBUTE_ALIAS
      column_names + _ransackers.keys + _ransack_aliases.keys +
      attribute_aliases.keys
    else
      column_names + _ransackers.keys + _ransack_aliases.keys
    end
 end

 # Ransackable_associations, by default, returns the names
 # of all associations as an array of strings.
 # For overriding with a whitelist array of strings.
 #
 def ransackable_associations(auth_object = nil)
   @ransackable_associations ||= reflect_on_all_associations.map { |a| a.name.to_s }
 end

がっつりコメントアウトされとるやんけ!!!!!!!!

# Ransackable_attributes, by default, returns all column names # and any defined ransackers as an array of strings. # For overriding with a whitelist array of strings. # ちょっとした時に使う分には全ての columnにたいしての検索でもいい。ということからデフォルトは全ての columnをreutrnしている。

しかしながら、悪意のあるユーザにとってはこれがSQLインジェクションの入り口になったり? インジェクションはできなくても製作者が意図してない検索をさせることも容易に想像ができます。

そのため今回のプロジェクトでは該当メソッドをオーバーライドして検索をかける場合は自分が許可したものしか通さないんですね。 うーんStrongParameterに似ている気がするw

ちなみに改めてREADMEをみていると

Authorization (whitelisting/blacklisting)

ちゃんと記載してありました。Document読みましょう。

まとめ。

documentを読みましょう。答えはそこにある。。

とりあえずRubyが動くまでの環境構築メモ

必要なもの

  • エディタ
  • HomeBrew(以下の管理のため)
    • rbenv(rubyを管理する)
    • mysql(今回は5.7入れたい)

エディタ(高機能なメモ帳)

以下のうちどれか一つ。オススメ順

HomeBrew

以下ターミナルでの操作

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

時間かかる -> おわったら

 brew doctor

→ command not foundじゃなければおk

変なwarningがでていたら → https://qiita.com/unsoluble_sugar/items/acaffa6d0e28c3c24934 頑張れそうなら解決してみて

rbenv(rubyを管理する)

brew install rbenv ruby-build

-> rbenv --version

→ command not foundじゃなければおk

echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

source ~/.bash_profile

(変化なくて問題ない)

ruby の 2.5.0を入れる

rbenv install 2.5.0

rbenv versions

-> 2.5.0があればおk

rbenv global 2.5.0

rbenv rehash

ruby -v

-> 2.5.0ならおk

mysql

brew install mysql@5.7

brew link mysql@5.7

mysql --version

-> Command not Foundじゃなければ なんかワーニングでてたらそれ打てばおk

MySQLを立ち上げるには、
次のように入力して、エンターキーを押します。

$ mysql.server start

MySQLを終了するには、
次のように入力して、エンターキーを押します。

$ mysql.server stop

サーバにインストールしたMySQLは、常時起動するようにするのですが、
ローカル環境でMySQLの学習以外の作業もすると思いますので、
MySQLは、使う時に立ち上げて、使い終わったら、停止しておくのが良いと思います。
再起動はこれ。
$ mysql.server restart

MySQL のステータス確認
次のように入力して、エンターキーを押します。

$ mysql.server status
起動している場合はこのように表示されます。
SUCCESS! MySQL running (13035)

停止している場合はこのように表示されます。
ERROR! MySQL is not running

command not foundは基本的にNGなのでその時はがんばること。