- 投稿日:2019-03-01T22:44:08+09:00
VSCodeを使ったRuby開発環境をMacで作成
背景
Ruby on Rails チュートリアル をおこなうため
Cloud9ではなく、ローカル端末内に環境を作成した。使用環境
- MacBook Pro (15-inch, 2018)
- macOS Mojave 10.14.3
- VSCode 1.31.1
Ruby on Railsのインストール
こちらを参照してください。
自分がおこなったときの補足ですが
Homebrewを1.9.2から2.0.2にアップデートするとき
フリーズしているのでは?と思うくらい時間がかかりました。進捗を確認するため、以下のコマンドでアップデートしました。
brew update -vVSCodeのダウンロード
https://code.visualstudio.com/
「Download for Mac」クリック
(Stable版のダウンロードが開始)Stable:「安定版」
Insiders:「最新版」Insiders版は新機能やバグフィックスが先取りされているが
動作が不安定とのことなので、Stable版を選択しました。VSCodeの日本語化
左の赤矢印のアイコンをクリックし、検索欄に"Japanese"と入力すると
「Japanese Language Pack for」が出てくるので"Install"を選択。
メッセージが表示されるので"Restart Now"をクリック。VSCodeが再起動されたら、日本語表示に切り替わっています。
拡張プラグインの追加
日本語化の方法と同じく、拡張プラグインで
Ruby開発に適したプラグインをインストールする。
※とりあえず最小限にしてみました。Ruby
各種gemを使用するため、必ず入れること。
vscode-icons
各ファイルの拡張子で判断して、アイコンを表示してくれる。
endwise
正しいインデントレベルを保ちながら
Rubyコードの構造に"end"を追加してくれるeuby-rubocop
Rubyのコーディング規約に準拠しているかチェックすることのできる”rubocop”が使用できる。
”rubocop”についてはこちらを参照。その他
チュートリアルを進めていき
必要なもの、便利なものを見つけた際は
こちらに反映させていく予定です。何かおすすめの拡張機能、設定方法などがありましたら
教えていただけますと幸いです。
- 投稿日:2019-03-01T22:44:08+09:00
MacOSXでRuby用のVSCode環境作成
背景
Ruby on Rails チュートリアル をおこなうため
Cloud9ではなく、ローカル端末内に環境を作成した。使用環境
- MacBook Pro (15-inch, 2018)
- macOS Mojave 10.14.3
- VSCode 1.31.1
VSCodeのダウンロード
https://code.visualstudio.com/
「Download for Mac」クリック
(Stable版のダウンロードが開始)Stable:「安定版」
Insiders:「最新版」Insiders版は新機能やバグフィックスが先取りされているが
動作が不安定とのことなので、Stable版を選択しました。VSCodeの日本語化
左の赤矢印のアイコンをクリックし、検索欄に"Japanese"と入力すると
「Japanese Language Pack for」が出てくるので"Install"を選択。
メッセージが表示されるので"Restart Now"をクリック。VSCodeが再起動されたら、日本語表示に切り替わっています。
拡張プラグインの追加
日本語化の方法と同じく、拡張プラグインで
Ruby開発に適したプラグインをインストールする。
※とりあえず最小限にしてみました。Ruby
各種gemを使用するため、必ず入れること。
vscode-icons
各ファイルの拡張子で判断して、アイコンを表示してくれる。
endwise
正しいインデントレベルを保ちながら
Rubyコードの構造に"end"を追加してくれるeuby-rubocop
Rubyのコーディング規約に準拠しているかチェックすることのできる”rubocop”が使用できる。
”rubocop”についてはこちらを参照。その他
チュートリアルを進めていき
必要なもの、便利なものを見つけた際は
こちらに反映させていく予定です。何かおすすめの拡張機能、設定方法などがありましたら
教えていただけますと幸いです。
- 投稿日:2019-03-01T21:04:45+09:00
Ruby$_の意味と競プロでの実例
variable $_
最後に Kernel.#gets または Kernel.#readline で読み込んだ文字列です。https://docs.ruby-lang.org/ja/latest/method/Kernel/v/_.html
AOJで
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_4_Chttp://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=3405210#1
puts eval($_.chomp) while !gets["?"]参考
次にやること
AOJ解き直す
- 投稿日:2019-03-01T20:58:08+09:00
RailsでCSVファイルのデータをDBに取り込む
これまで「CSVファイルのデータを取り込んで表示する」という経験がなかったのですが、とある課題の中で必要になったので備忘録。
Ruby 2.5.1
Rails 5.2.2RubyのCSVライブラリを利用する
「使いたい/欲しいと思った機能は大抵既に実装されている」みたいなことは勉強していく中でよく聞く言葉だが、CSVファイルを扱う機能もそれに違わず実装済み。
https://docs.ruby-lang.org/ja/latest/library/csv.html
CSVライブラリはその名の通りCSVファイルを扱うライブラリ。
CSVライブラリには例外クラスも含めると5つのクラスがあるが、今回は割愛。
CSVクラス
https://docs.ruby-lang.org/ja/latest/class/CSV.html
このクラスは CSV ファイルやデータに対する完全なインターフェイスを提供します。
CSVにあるデータを取り込む場合には、CSVクラスを使う。
CSVクラスには特異メソッドとして以下のものがある
filterforeachgenerategenerate_lineinstancenewopenparseparse_linereadreadlinestable特異メソッドとはクラスではなくある特定のオブジェクトに固有のメソッドのことCSV.foreachメソッドでCSVファイルを読み取る
CSVクラスにはCSVファイルを読み込んだり書き込んだりする特異メソッドが複数あるが、CSVファイルを読み込む場合は主にCSV.foreachを使う
CSV.foreachメソッドforeach(path, options = Hash.new) {|row| ... } -> nil** ->CSVの各行が、与えられたブロックに渡される・path
CSVファイルが格納されているパスを指定する。相対パス相対パスとは、起点となる位置からみたディレクトリ及びファイルの表現方法。 起点となる位置から階層を1つ上がる場合には`../`を使い、特定のディレクトリに入る場合には`ディレクトリ名/`を使う・options
CSV.foreachのオプションには、CSV.newと同じオプションを取ることができる。
-> https://docs.ruby-lang.org/ja/latest/method/CSV/s/new.html
特に使うケースが多そうなのがheadersオプション。以下リファレンスマニュアルからの引用です。
:first_row というシンボルか真を指定すると、CSV ファイルの一行目をヘッダとして扱います。
headers: trueをオプションに渡せば1行目はヘッダとして読み込まないようになる。
CSVファイルでは1行目には各カラムの名前などを入れるケースも多いので、このオプションを使うことも多そう。db/seeds.rbでCSVファイルを読み込ませ、データを取り込む
CSV.foreachでCSVファイルのデータを取り込めるようになったら、そのデータをseeds.rbからデータベースに取り込む。
CSV.foreachメソッドではCSVのデータを1行ずつブロックに渡していくので、以下のようなコードで対応するテーブルに値を渡す。
user.csvID, Name, Email, City 1, Sato, hoge@example.com, Tokyo 2, Suzuki, foo@example.com, Osaka 3, Tanaka, bar@example.com, Fukuokadb/seeds.rbrequire 'csv' CSV.foreach(*path, headers: true) do |row| User.create( username: row['Name'], email: row['Email'], city: row['City'] ) end上記のコードで、CSVのデータがDB上に読み込みできるようになる。
ここまで書いたらbin/rails db:seedでデータを読み込ませれば完了。他に何か方法あるのかも調べたい。
- 投稿日:2019-03-01T14:58:11+09:00
[Ajax+Rails]プレビューで個別削除可能な画像アップローダの作成
RailsでAjaxを使って、画像アップローダーを作成しました。想定しているのは、メルカリのようなユーザーが商品を出品し、取引を行うサイトの出品画面です。できたことは以下です。
- ドラッグ&ドロップで画像をアップロードし、結果を送信する前にプレビューをする。
- そのほかのフォームの結果と一緒に画像をコントローラに送信する。
- 画像のプレビュー時に、削除ボタンで個別にアップロードする画像を変更する。
環境
Rails 5.0.7.1
ruby 2.3.1注意点
- Rails初学者のため、間違っている部分が多々ある可能性がありますので、参考程度にご覧ください。
- 実際に動いているコードから編集を加えているため、動作保証ないです。すいません。。。
- モデル側については、解説ありません。コントローラ、ビュー、javascript部分になります。モデル側は、itemに対して複数のimagesテーブルのレコードを登録できるような中間テーブルを作成しています。
1.ビュー
new.html.haml/ form_forを利用して、itemのモデルオブジェクトにデータを送信する。 = form_for @item, html: {id:'new_item'} do |f| / 中略 .item__images__container .item__images__container__preview / 以下のulタグの下に、Jsからli要素を挿入することでプレビューを実現します。 %ul .item__images__container__guide / ドラッグ&ドロップエリアをプレビューによって変動させたい場合以下のようなclassを作成し、プレビュー画像の数によってclassを変える。 .have__image--0 %h5 ドラッグ&ドロップ<br>でファイルをアップロード / 中略(そのほか様々なフォームがある想定) .item__form__sellcontent__submit__done = f.submit class: 'btn-default item__done', disable_with: "Save", value:"出品する"ドラッグ&ドロップで、画像アップローダを作成するため、ビュー側には、inputタグは必要ありません。(もし、inputタグを利用して実装可能ならば、ご教示いただきたいです。。。)
ビューについては、
- プレビューの画像と削除ボタンのHTMLを挿入するためのulを設置する。
- ドラッグ&ドロップのためのエリアを設定する。(今回の場合は、.item_imagescontainer_guide)のみでOKです。
2.コントローラー
items_controller.rbdef new @item = Item.new end def create # itemが保存できたかどうかで、画像の保存を分岐させたいために、newです。 @item = Item.new(create_params) if @item.save image_params[:images].each do |image| #buildのタイミングは、newアクションでも可能かもしれません。buildすることで、saveした際にアソシエーション先のテーブルにも値を反映できるようになります。 @item.images.build item_image = @item.images.new(image: image) item_image.save end #今回は、Ajaxのみの通信で実装するためHTMLへrespondする必要がないため、jsonのみです。 respond_to do |format| format.json end end end private def create_params # images以外の値についてのストロングパラメータの設定 item_params = params.require(:item).permit(:name, :description,:category_id, :size, :brand_id, :condition, :select_shipping_fee, :shipping_method, :area, :shipping_date, :price) return item_params end def image_params #imageのストロングパラメータの設定.js側でimagesをrequireすれば画像のみを引き出せるように設定する。 params.require(:images).permit({:images => []}) endコントローラーの特徴としては、itemsとimagesの二つのテーブルを更新するためにストロングパラメータを二つ設定することです。その際に、imagesのアップロードデータのparamsのkeyを:itemにしていると、itemを保存する際に、imagesの値が許可されいないのにも関わらず、値を持っているため、unpermitted parameterが出てしまいます。他にも対処があるかもしれませんが、僕は、keyを:imageに設定することでunpermitted parameterのエラーが出ないようにしています。
(通常、form_forでモデルオブジェクトを設定すると、name属性が"item[description]"となりますが、このitem部分をimageに変更してjsで送ることでparamsのkeyを変更できます。)3.Javascript部分
かなり長くなりますが、ご了承ください。
3.1 ドラッグアンドドロップおよび画像読み込み
item_new.js// プレビューに挿入するHTMLの作成 function buildImage(loadedImageUri){ var html = `<li> <img src=${loadedImageUri}> <div class="item__images__container__preview__box"> <div class="item__images__container__preview__box__edit" > 編集 </div> <div> <a class="item__images__container__preview__box__delete">削除</a> </div> </div> </li>` return html }; // 画像を管理するための配列を定義する。 var files_array = []; // 通常のドラッグオーバイベントを止める。 $('.item__images__container__guide').on('dragover',function(e){ e.preventDefault(); }); // ドロップ時のイベントの作成 $('.item__images__container__guide').on('drop',function(event){ event.preventDefault(); // 何故か、dataTransferがうまくいかなかったので、originalEventから読み込んでいます。 // ここで、イベントによって得たファイルを配列で取り込んでいます。 files = event.originalEvent.dataTransfer.files; // 画像のファイルを一つづつ、先ほどの画像管理用の配列に追加する。 for (var i=0; i<files.length; i++) { files_array.push(files[i]); var fileReader = new FileReader(); // ファイルが読み込まれた際に、行う動作を定義する。 fileReader.onload = function( event ) { // 画像のurlを取得します。 var loadedImageUri = event.target.result; // 取得したURLを利用して、ビューにHTMLを挿入する。 $(buildImage(loadedImageUri,)).appendTo(".item__images__container__preview ul").trigger("create"); }; // ファイルの読み込みを行う。 fileReader.readAsDataURL(files[i]); } });読み込み部分は、「Javascript ドラッグ&ドロップ」を検索すると、比較的たくさん出てきます。他のものと異なるのは、読み込み動作時に、files_arrayに画像ファイルを追加していることです。最終的に、このfile_arrayに存在している画像を送信します。配列に代入する目的は二つあります。
- 画面遷移せずに、再度画像がドラッグ&ドロップされた際に、前回の画像ファイルを保持する。
- プレビューで画像が削除された際に、該当画像を特定し、送信する画像を削除する
簡単に言うと、JS側に画像を削除・追加可能なDBを配列で作成して、コントローラーへの送信が行われるまで管理するために利用します。
3.2 プレビューからの画像削除
item_new.js// div配下のaタグがクリックされた際に、イベントを発生させる。 $(document).on('click','.item__images__container__preview a', function(){ // index関数を利用して、クリックされたaタグが、div内で何番目のものか特定する。 var index = $(".item__images__container__preview a").index(this); // クリックされたaタグの順番から、削除すべき画像を特定し、配列から削除する。 files_array.splice(index - 1, 1); // クリックされたaタグが含まれるli要素をHTMLから削除する。 $(this).parent().parent().parent().remove(); });先ほど、プレビューとして追加されたli要素は、個別にそれぞれの画像を特定する要素が含まれいません。(例えば、liのクラスにナンバーをカスタムクラスで通し番号をふるなどが行われていない。)そのため、何番目のli要素が削除のイベントを受けたのかをindex()で何番目のaタグがクリックされたかを特定することで特定しています。これによって、何番目に挿入した画像かを判別し、file_arrayから削除しています。
3.3 出品フォームのコントローラへの送信
item_new.js// submitボタンが押された際のイベント $('#new_item').on('submit', function(e){ e.preventDefault(); // そのほかのform情報を以下の記述でformDataに追加 var formData = new FormData($(this).get(0)); // ドラッグアンドドロップで、取得したファイルをformDataに入れる。 files_array.forEach(function(file){ formData.append("image[images][]" , file) }); $.ajax({ url: '/items', type: "POST", data: formData, contentType: false, processData: false, dataType: 'json', }) .done(function(data){ alert('出品に成功しました!'); }) .fail(function(XMLHttpRequest, textStatus, errorThrown){ alert('出品に失敗しました!'); }); });items_controllerへの送信は、ajaxのみで行うため、画像以外の値を先に、formDataに追加します。その後、files_arrayに入っている画像をimage[images][]と言うkeyでformDataに追加します。この際、controllerの部分で説明したようにimage[]と言う形式で送ることで、コントローラ側で受け取った際に、paramsのkeyをimageとしてデータを送ることができます。
以上、js部分になります。
まとめ・ポイント
- fromData.append()を利用することで、jsで取得した値をajaxで送信することができる。
- js側に配列などを作成することで、ビューで削除された画像を削除できるようにする。
- 本当は、Ajaxではなく通常のHTMLで行いたかったのですが、どうしてもできなかったのでAjaxで実装しました。他の方法もあるかと思います。(どうしてできなかったのかは、おまけに書きます。)
- 今回は、出品画面のみですが、更新画面は大幅にjsを変更することが必要です。(DBに保存された画像と新規登録画像を判別する必要があるため)
おまけ
なぜ、inputタグで作成できなかったのか。
理由1:inputタグのtype=fileのvalueにjs側から値を挿入できない。
ドラッグ&ドロップでの画像アップローダーは、jsでしか実装できないため、inputタグのtype=fileに取得した値を挿入しようとしたのですが、反映されない。調べてみると、下記のようにセキュリティ上値を入れることができなそうなことが分かり、断念した。
INPUT TYPE="FILE"の初期値をセットする方法
NPUT TYPE=FILEタグでの入力値保持について理由2.ajaxとhtmlで分けてテーブルに登録できるかわからなかった
試していないのですが、ajaxで画像をそれ以外をhtmlを送信することを考えましたが、itemが保存できなかった時にimageの処理を止めることがどうしたらいいかわからなかった(逆も同じ)。
なんとなく、buildを利用すればなんとかなるような気がしたが、一緒にデータを送った方が安全だと判断した。理由3.input multiple= trueは、過去の値を保持できない
input multiple=trueを利用すれば簡単に複数画像をinputタグで渡すことができるのですが、画面遷移せずに再度inputタグの値を更新すると前回の値はなくなってしまうため、HTMLのみでは複数回のファイルアップロードにどのように対応していいかわからなかった。
以上になります。他のやり方がありましたらご教示いただきたいです。(CarrierWaveの機能をフルに使えばできそうな気もするのですが、、、公式のgitを読み解くことができませんでした。。。)
参考リンク
ドラッグ&ドロップで複数画像をアップロードする
CarrierWave Upload Multiple Images [2018 Update]
CarrierWave 複数の画像をコード三行で一つのカラムに保存する
- 投稿日:2019-03-01T14:45:52+09:00
社内で行なった Ruby Style Guide勉強会について
背景
私たちの会社(エイチーム引越し侍)では、長らくバックエンドでPHPを使ってきた歴史がありますが、
最近はRubyを使うことも多くなってきました。
でも、Rubocopさんに怒られる日々。
これじゃあいけない。
ということで、社内でRubyのStyle Guideを勉強しようという話になりました。
数名を集め、議論をしながらスタイルガイドを作成していきました。ゴール
https://github.com/rubocop-hq/ruby-style-guide
https://github.com/airbnb/ruby
https://github.com/cookpad/styleguide
この辺りを教材として、引越し侍Ruby Style Guideを作成するところまで注意事項
本記事はまだ未完成となっております。(ので、これが完全に良い書き方だ!というつもりはございません。)
ノウハウがたまるごとにアップデートを行います。
ご意見等ある方はコメント欄に記載していただけると、勉強になるので、是非お願いいたします。引越し侍
Ruby Style Guideインデント系
【MUST】 メソッドのインデントには2つのスペースで統一
コードが右に長くなりすぎず見えやすい
# Bad def sample_method do_something end # Good def sample_method do_something end【議論】
異論なし
見やすい & Ruby規約なのでという理由で1秒で決定【MUST】
case ~ when文には、スペースを入れない
case ~ whenはif ~ elseと同じ扱いなので、入れないのが良い# Bad case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end # Good case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end【議論】
冒頭に話した通り我々はPHP脳の人間なので、switch ~ case文同様、1つめがいいという議論が生まれました。
ただ、if ~ elseと同じ扱いという事には納得。
rubyの文化に慣れようという結論になりました。【MUST】 複数行にメソッドが連なる場合はドットの位置を合わせる
まだメソッドが続いているということがわかり、かつドットが揃っていて見やすいため
# Bad User.active .some_scope(foo) # Bad User.active .some_scope(foo) # Good User.active .some_scope(foo)※ ドットが上か下かという議論は改行の項目を参照
【議論】
2つめの方が.の位置を合わせるために、スペースを合わせなくていいのでいいという意見もありました。
1人がスペースを合わせるだけで見やすくなり、のちにそのコードを見る10人の人の時間を削減できたならそれがいい!という結論で終わりました。【MUST】 複数行に連なるBooleanの改行は2スペース開ける
Booleanの判定がまだ続いていることを判別しやすいため
# Bad def eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end # Good def eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end【議論】
異論なし
Rubyでは&&も下に下ろせないため、これが最適だろうという結論インラインスペース系
【MUST】 インラインコメントは半角スペースを開ける
その方がとても見やすいため
# Bad result = func(a, b)# we might want to change b to c # Good result = func(a, b) # we might want to change b to c【議論】
満場一致で合意
ただ、右に長くなってしまうため、基本的にコメントは上に書いて欲しいという議論が生まれました【MUST】 オペレーター、コンマ、コロン、セミコロン、
{}の後には半角スペースをいれるその方が見やすいため
# Good sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false [1, 2, 3].each { |e| puts e }【議論】
異論なし
ただ、eachをdo ~ endで書かないのかという論争に発展
こちらについては、下で別途議論しました【MUST】 コンマの前にはスペースをいれない
英語では
,の前にスペースを入れないためそちらの方が見やすいため# Bad result = func(a , b) # Good result = func(a, b)【議論】
異論なし
どの言語も共通して、コンマの前にスペースは入れないが、
なぜここだけ入れないのかという議論がありました。
そこで考えたものがこちらです英語では
,の前にスペースを入れないためそちらの方が見やすいため【MUST】 文字列中の変数展開にスペースを入れない
展開する場所の前後にスペースがある場合、展開の中にもスペースがなく、可読性が高いため
# Bad var = "This #{ foobar } is interpolated." # Good var = "This #{foobar} is interpolated."【議論】
こちらの方が見やすいため【MUST】 rangeの
...の前後にスペースを開けないこちらの方が可読性が高いため
# Bad (0 ... coll).each do |item| # Good (0...coll).each do |item|【議論】
異論なし
終端を含む...と終端を含まない..共にGoodの方が見やすいよねということで決着改行系
【MUST】 区切り文字は
;ではなく、改行する無駄に右側にコードが長くならずに綺麗に見えるため
# Bad puts 'foo'; # Bad puts 'foo'; puts 'bar'; # Good puts 'foo' puts 'bar'【議論】
異論なし
そもそもRubyで;使えるんだ、、、意見も【MUST】 メソッドのパラメーターが多い場合、一行ごとに改行する
その方が見やすいため
# Bad def create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # Bad for samurai def create_translation( phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification ) ... end # Good for samurai def create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end【議論】
ここはすごくもめました
決めの問題かとは思いますが、2つめのものだと、defの下に処理を記述して言った時に、
パラメータのインデントと処理のインデントが同じになるため、見にくいということで3つめのもので決着しました。【MUST】 複数行にメソッドが連なる場合は
.を下におろす我々は、PHPでも
->を下におろしており、慣れしたしんでいて、見やすいため
※ Rubyコミュニティではどちらで見やすいため、OKという見解# Bad for samurai User.active. first_scope(foo). second_scope(bar) # Good for samurai User.active .first_scope(foo) .second_scope(bar)※ インデントに関してはインデントを参照
【議論】
AirbnbさんやCookpadさんは1つめのものを推奨しています。
ドットを下ろし、かつインデントを2つに統一しようとするとUser.active .some_scope(foo)となり、ドットの位置が微妙になるため、彼らの定義には納得です
ただ、ドットをあげたものがどうしても我々には見にくいため、ドットの位置も合わせてやることで決着Collection
【MUST】 配列やハッシュから要素を取り出したい場合は、
findを使わずにdetectを使う
ActiveRecordのfindメソッドと混同せずに、それがcollectionだということがわかるため【議論】
本当に混同するかどうかを議論しましたが、実際に混同してしまったという人がいたため、採用しました。【MUST】
collectよりもmapを使用してくださいjsなどでも使える
mapの方が、親しみやすいため
※ どちらも同じ動きをする【議論】
満場一致でmapの方が親しみやすいとのことで異論なし【MUST】
injectではなく、reduceを使ってください同じ動きをしますが、"配列を折り畳む"という意味が伝わりやすい
reduceを使ってください
また、PHPやSwiftなど他の言語でも実装されているreduceの方が親しみやすいですnumbers = [4, 3, 9, 8, 5, 6, 1, 7, 2] puts numbers.reduce {|sum, n| sum + n } > 45 # ブロックの第一引数である初期値は以下のように定義できます puts numbers.reduce(100) {|diff, n| diff - n } > 55【議論】
異論なし
そんなに使うことがないため、白熱もせず、、【MUST】
countやlengthよりもsizeを使うようにする
sizeの方速いため【議論】
え、、全然countとか使ってるわ、、
本当に遅いの?という議論
TODO: 本当に遅いか調べる(知っている方はコメントお待ちしております。)【MUST】 中身のない
Array、Hashは[]、{}で初期化こっちの方がわかりやすいし、シンプルだから
# Bad arr = Array.new hash = Hash.new # Good arr = [] hash = {}【議論】
異論なし
%リテラル【MUST】
%()による文字列宣言を使う場合は、1行かつ挿入変数があるかつダブルクウォートを使っているもののみに限り使うそれ以外は適切な宣言方法があるため
# Bad %(<div class="text">Some text</div>) # Good # '<div class="text">Some text</div>' # Bad %(This is #{quality} style) # ダブルクォート使った方がスマート "This is #{quality} style" # Bad %(<div>\n<span class="big">#{exclamation}</span>\n</div>) # heredocの方がスマート<<EOS # <div> # <span class="big"> # #{exclamation} # </div> # EOS # Good %(<tr><td class="name">#{name}</td>)【議論】
%()は便利だし、綺麗にかけるからGood!という結論に
異論なし【MUST】 文字列の配列は
['sample', 'today']ではなく%wの形で初期化
%wの方が新しく追加された構文で、タイプ数が少なくて済むため
ただし、スペースを含む場合は['1st day', 'today']という形で初期化する# Bad for samurai STATES = ['draft', 'open', 'closed'] # Good for samurai STATES = %w(draft open closed) # Good STATES = ['draft', 'open', 'closed', 'already deleted']【議論】
いつもrubocop怒ってくるけど、%wって本当に必要?
という議論が生まれました
%wとか%iはrubyでしか使わない構文で直感的ではないのでは?という意見がでました
調べて見たところ、
1. 速くかける
2.%wという構文を知ってさえいれば、無駄なものを書かなくてもString型の配列であることがわかる
というメリットがありました
ただ、確かに多く書くときは便利だし、これが文字列の配列であることは慣れの問題だけなので、時代の流れにそって採用という結論に【MUST】 リテラルの配列は
[:sample, :today]ではなく%iの形で初期化
%iの方が新しく追加された構文で、タイプ数が少なくて済むため# Bad for samurai STATES = %i(draft open closed) # Good for samurai STATES = [:draft, :open, :closed]【議論】
上と同様の議論をしました【MUST】 スペースを含むシンボルの初期化は
%sではなく、:"sample symbol"の形で初期化ほぼ使うことのない
%sがあると、次見た人がわざわざ調べないといけないが、:"sample symbol"の形で書かれて入れば、それが何か一目でわかるため
※rubyコミュニティでも%sは使わない方針に変更# Bad %s(Hello World) # Good :"Hello World"【議論】
異論なし
ほとんど使うことないと思うけど、確かにハイフン-は使ったことあるので、採用メソッド系
【MUST】 必要ない時は、
class << selfを使わず、self.を使う
self.を使っていた場合はそのメソッドを見ればすぐにselfメソッドであることがわかる。
ブロックで定義すると、(ブロックの中が肥大化しているなどの理由で)すぐにselfメソッドであるかどうかがわからないclass TestClass # Bad class << self def first_method ... end def second_method ... end end # Good class << self attr_accessor :per_page alias_method :nwo, :find_by_name_with_owner end def self.first_method ... end def self.second_method_etc ... end end【議論】
異論なし【MUST】 引数なしのメソッドは
()を省略、引数があるときは必ず()を書くパラメータの有無を明示的に分けることができるから
# Bad def some_method() # body omitted end # Good def some_method # body omitted end # Bad def some_method_with_parameters param1, param2 # body omitted end # Good def some_method_with_parameters(param1, param2) # body omitted end【議論】
異論なし【MUST】 引数のあるメソッド呼び出しは、メソッドの後にスペースを入れずに
f(params1, params2)の形で書くメソッドの定義と同じ形式でかけるようにするため
# Bad some_method (params1, params2) # Good some_method(params1, params2)【議論】
異論なしその他
【MUST】 一行の長さは100文字以内
一行が右によりすぎずエディタに表示できる範囲内だから
【議論】
なぜ100文字なのかという議論がありましたが、エディタに表示できる限界がこれぐらいだろうということと、
これ以上長くしていい事なんかないと言うことで決着最後に
最初にも記載させていただいた通り、本記事はまだ未完成となっており、内容をアップデートする可能性がございます。
この書き方が万人に良いというものではなく、自分たちに合った書き方を模索している状態になります。
ご意見等ある方はコメントに記載していただけると幸いです。(勉強させていただきます!!)
- 投稿日:2019-03-01T14:32:26+09:00
【個人開発】絶対炎上しないSNSをRailsで開発した
きっかけ
TsubusyというSNSを開発しました。
情報系の学科に在籍している大学生です。
プログラミング自体はとても楽しくて好きなのですが、自分で何かを作り出した経験がないなとふと気付きまして、Railsを勉強してWEBアプリケーションを作ってやろう!と思い立ちました。
また、はてなの匿名日記を見て、こういう匿名性の高めなインターネットが懐かしくそれに近いSNSのようなものを作れないか、と思っていたところでした。
そこで、返信が直接自分の投稿にぶら下がらないボトルレターのようなSNSを作ればいいんじゃないか?ということを思いつき、実際に実装していきました。使用した技術
Ruby on Rails
Bootstrap
nginx
などなど・・・内容・特徴
基本的にはボトルレターを想像してもらえばいいのではないかと思います。投稿した内容は検索機能やボヤージ機能によって他の人に届きます。
最近のSNSでは自分の興味を持っている対象(フォローしている人、または見た内容など)を元にサジェストされることが多いと思うのですが、このサイトではそういった機能は一切無く、検索機能・及びボヤージ機能(ランダムに投稿を表示する機能)のみによって他の人が投稿した内容を見ることができます。
この画像はボヤージ機能によるものです。全くランダムに他の人の投稿が抽出され、表示されます。また、他の投稿に対してお気に入りボタン以外でレスポンスを返すことはできません。ので、投稿した内容についてのレスポンスは基本的にはお気に入りの数だけでわかるということになります。また、自分の投稿した内容が合計どれくらいお気に入りされているかはプロフィールから確認することができるので、それによって自分の投稿した内容がどれくらい見られているかがわかります。
制作のあれこれ
この仕組みを思いついたのがだいたい半年前くらいだったので、だいたい半年くらいかかってリリースしたことになります。とはいえ、正直同じペースで開発できていたわけではないので、まあまあ頑張って開発できたのではないかなと思っています。
フレームワークとしてdjangoや他のフレームワークを利用するということも考えられたのですが、WEBアプリケーションを作るのが初めてであったという点、日本語での情報が豊富であろうという点からRailsを選択しました。途中でなんども詰まるところがあったのでこれは良い選択だったのではないかと思っています。
また開発していて思ったこととして、やはり英語の情報が圧倒的に多いなということは確実に感じました。僕自身英語が全く読めないということはないのですが、どうしても日本語に比べて読むスピードが落ちてしまうことや専門用語などよくわからない単語が多く英語で読む負担が大きいのでできるだけ日本語での情報を求めてしまう傾向がありますね。課題
正直デザインに関しては詰めきれていないというか、もっと良くできるのではないかなという気がしています。
それに加えて、自分の投稿に対するフィードバックを得づらいのではないかとも少し思っているので、そのあたりのバランスをもう少し考えていく必要があるのではないかなと思います。最後に
なにかご意見などありましたら、ツイッターまでご連絡お願いします。また私事ですが、現在アルバイト(先)募集中なのでなにかありましたらDMまでお願いします
- 投稿日:2019-03-01T13:17:38+09:00
差分を求める
Rubyには差分を求めるライブラリが存在する
require 'diff/lcs'
Diff::LCS.diff(A, B): 配列の要素に差があれば差分をとるDiff::LCS.diff([2, 3, 4, 'b'], [1, 2, 3, 'a', 'b']) #=> [[["+", 0, 1]], [["-", 2, 4], ["+", 3, "a"]]]
Diff::LCS.sdiff(A, B): 配列の要素1つごとに差分があるかを返すDiff::LCS.sdiff([2, 3, 4, 'b'], [1, 2, 3, 'a', 'b']) #=> [["+", [0, nil], [0, 1]], ["=", [0, 2], [1, 2]], ["=", [1, 3], [2, 3]], ["!", [2, 4], [3, "a"]], ["=", [3, "b"], [4, "b"]]]
Diff::LCS::Changeオブジェクトに使えるメソッド
:<=>,:==,:inspect,:to_a,:new_element,:old_position,:new_position,:old_element,:changed?,:action,:adding?,:deleting?,:unchanged?,:finished_a?,:finished_b?,:<,:>,:<=,:>=,:between?,:tap,:public_send,:instance_variables,:instance_variable_set,:instance_variable_defined?,:remove_instance_variable,:private_methods,:kind_of?,:is_a?,:instance_variable_get,:instance_of?,:public_method,:extend,:define_singleton_method,:singleton_method,:to_enum,:enum_for,:===,:=~,:!~,:eql?,:respond_to?,:freeze,:display,:object_id,:send,:to_s,:method,:nil?,:hash,:class,:singleton_class,:clone,:dup,:itself,:taint,:tainted?,:untaint,:untrust,:trust,:untrusted?,:methods,:protected_methods,:frozen?,:public_methods,:singleton_methods,:!,:!=,:__send__,:equal?,:instance_eval,:instance_exec,:__id__
- 投稿日:2019-03-01T13:06:06+09:00
CでRubyの拡張ライブラリを作った
はじめに
この記事を書いた人間はプログラミング歴1年以下の超がつくレベルの初心者です。
ところどころ分かりにくいところや間違いがあると思いますのでお気づきになった際にはコメントを残してくださると幸いです。作ったもの
Rubyからマウスを操作するための拡張ライブラリ
使った言語
・C(ライブラリ本体を記述)
・Ruby(モジュール)概要
ソースコードはこちら
- マウスカーソルの座標を取得したり、カーソルを動かしたりできます。
- 左クリックと右クリックを出力することも可能です。
- Cのwindows.hをインクルードしているのでWindows専用です。(Windows以外の環境が手元にないため未検証ですが恐らくそうです)
- 32bitの環境でコンパイルしているので64bitのマシンでは動作しません。(検証済み)
- 環境が整ったら64bit版も上げようと思います。
- Rubyが動作する環境でご利用下さい。
使い方
require 'mouse'
または
(このライブラリを利用するスクリプトが同じディレクトリにある場合)
require_relative 'mouse'定義されているメソッドと定数
getCursorPosX()
- カーソルのX座標を取得します。
getCursorPosY()
- カーソルのY座標を取得します。
setCursorPos(x,y)
- カーソルの位置を移動します。第一引数が移動先のX座標、第二引数はY座標を指定してください。
sendMouseEvent(key)
- マウスの左右ボタンの仮想キーコードを出力するメソッドです。
- 引数には整数または以下の定数を渡してください。
M_L_DOWN (= 2)#マウス左ボタンが押された状態
M_L_RELEASE (= 4)#マウス左ボタンが離された状態
M_R_DOWN (= 8)#マウス右ボタンが押された状態
M_R_RELEASE (= 16)#マウス右ボタンが離された状態
getKeyState(key)
- マウスまたはキーボードの特定のキーが押されているかを調べます。
- このメソッドは現在開発中のキーボードを操作するためのライブラリでも実装する予定です。
- 指定されたキーが押されていないときは0,押されているときはそれ以外の整数を返します。
- 引数には整数または前項の定数を渡してください。
is_cursor_moving?(arg = 0.001)
- 引数に指定された間隔でカーソルの位置を比較します。単位は秒です。
- 戻り値は、移動していれば
true,していなければfalseです。- そのため、
argの値が大きいとカーソルが移動しているか正しく判定できない場合があります。
- 投稿日:2019-03-01T12:44:28+09:00
RailsをGoogle App Engine�(Flexible Environment)で動かしてみた感想
2018年末に仕事でGoogle App Engine(GAE)のRailsアプリをリリースしました。
個人としても会社としてもGAEでRailsアプリをリリースするのは初めてだったので、動かしてみた感想などを共有したいと思います。
利点
- 手軽に始められる
- httpsのアプリで動かせる(オレオレ証明書とか必要ない)
- デプロイの安定感が高い(イミュータブルデプロイメント)
手軽に始められる
なんといってもこれが大きいです。
基本Flexible Environment(FE)はdockerで動くようにコードを書いてれば動くので、app.yamlという設定ファイルだけ用意してdeployすればすぐ動いてくれます。app.yamlenv: flex runtime: custom service: default automatic_scaling: min_num_instances: 1お手軽さはherokuとほぼ変わらず、GCPの事前知識不要でだいたい動かせるのが魅力です。
(最近のherokuを使っていないので、比較はできないですけども...)httpsで動かせる
ローカルでの開発ではオレオレ証明書とか色々考えないといけません。
が、GAEはhttpsのドメインを払い出してくれるので特に考えずにhttpsにできます。プロジェクトではfrontendにReact.js、backendにRailsという構成で、それぞれ別の人が開発するスタイルだったのですが、それぞれhttps対応するのに手間がかからなかったので結合もスムーズにいけました。
デプロイの安定感が高い
イミュータブルデプロイメントというらしいですが、GAEはバージョンごとに不変な環境を構築し、トラフィックの向き先をバージョンに割り当てられるようになっているため、安定したデプロイがしやすかったです。
既存で動いている環境を上書きしたりしないので、新しいバージョンにバグがあってもすぐトラフィックを前のバージョンに戻すことが出来たり、そもそもバージョンごとにURLが割り当てられるので、出す前のバージョンの動作確認をしてから切り替えることができました。
ブルー・グリーンデプロイメントに似てますが、ブルー・グリーンの2環境だけでなくバージョンの数だけ環境を持つことができる点ではこちらの方がより柔軟性が高いです。
またトラフィックを流す割合も設定できるので、カナリアリリースやA/Bテスト的な使い方もできるのも良さそうです(実際にはまだ試していないですが)。
欠点
いいところもありますが、もちろん欠点もあります。
- FEはdeploy超遅い。10分弱かかる
- SSHはできるけど、ちょっとの修正がめんどくさい
- 一番弱いインスタンスだと、rails consoleがメモリ不足でたまに落ちる
- トラフィックを受けないプロセスを動かすのはややこしい
deploy遅い & ちょっとの修正が面倒
これが割とつらいです。やばいミスった直そうというときにdeployに時間かかってしまって開発のスピードが出ません。
Standard Environmentは早いらしいんですが、FEだと時間がかかることが多いようです。上で書いたイミュータブル環境なおかげで(?)SSHで入っても書き換えで再構築ができないので、再deployする必要があって10分ほど待たされてしまいます。
rails consoleメモリ問題
単純に少しいいインスタンス使えばいいとは思いますが、rails server起動した状態でrails consoleやろうとするとメモリ不足で立ち上がってくれなかったりしました。
トラフィックを受けないプロセスを動かすのはややこしい
web serverのプロセスはGAEと相性がいいですが、例えばsidekiqなどのバッチのプロセスなどとはちょっと相性が悪そうです。
当たり前ですが、単純に起動しているインスタンスがある=プロセスが動いてます。
そのため、画面上トラフィック割り当てされてなくてもインスタンスさえ起動していれば、過去のバージョンであっても動いてしまっています。
特にsidekiqなどはredisのキューを見てプロセスが順次処理を実施していくので、過去のバージョンが残ってしまっているとたまにコード修正したのに直ってない!みたいな罠に陥ることがあります。
ということでバージョンを停止してからdeployすると、今度は一時的にダウンタイムが発生してしまうことになってしまいます。
トラフィック切り替えのように厳密に切り替わるわけではないので、重複期間を許すか、ダウンタイムを許すかはプロセスやサービスの仕組みごとに考えるほうが良さそうです。
というかそもそもGAEと相性が悪そうですね。
まとめ
最初始めるのはいいですが、慣れてきたらCI/CDがうまくできる環境に移行していくと開発のスピードを維持できそうです。
一方デプロイはやりやすいので、本番でうまく使うのは良さそうですね。
- 投稿日:2019-03-01T11:39:11+09:00
【Rails】renderでインスタンス配列を繰り返し処理したい【部分テンプレート】
もうeachをビューで使うなんて 言わないよ絶対。
renderでインスタンス配列だけを渡してクールにキメたい。
views/xxxs/xxx.html.erb<%= render @users %>この場合、
views/users/_user.html.erbの部分テンプレートを呼び出す
インスタンス配列@usersの中身が無くなるまで、繰り返し処理される
部分テンプレートファイルの_user.html.erbファイル内では、変数userを扱えるようになる
テンプレートファイル名は単数形であることに注意views/users/_user.html.erb<%= user.name %> #例として、nameカラムがある場合 #部分テンプレート内で使う変数名が単数形になっていることに注意
続いて、アソシエーションを組んでいる場合views/xxxs/xxx.html.erb<%= render @user.books %>この場合、Bookクラスのインスタンスとして扱われるので上記と差はあまりなかったりします。
views/books/_book.html.erbの部分テンプレートを呼び出す
インスタンス配列@user.booksの中身が無くなるまで、繰り返し処理される
部分テンプレートファイルの_book.html.erbファイル内では、変数bookを扱えるようになる
テンプレートファイル名は単数形であることに注意views/books/_book.html.erb<%= book.title %> #例として、titleカラムがある場合 #部分テンプレート内で使う変数名が単数形になっていることに注意
以上です!ご指摘等ありましたらコメント欄にお願いします!
- 投稿日:2019-03-01T07:34:36+09:00
Ruby メソッド
動作環境はMacを使用しています。
メソッド
複数の処理を1つにまとめて扱いやすくしたもの
クラス内に定義される
≒クラス内に定義する関数構文
def メソッド名(引数1、引数2...)
実行したい処理
end引数がない場合省略可。
引数は、メソッドに渡すもの。
実践
"Hello, World"と出力するプログラムを実装
メソッド名はhello_worldmethod_hello.rbdef hello_world puts "Hello, World!" end hello_world出力結果
$ ruby method_hello.rb Hello, World!引数を使用して、任意の数字を計算するプログラム
method_add.rbdef add(x, y) x + y end puts add(10,1) #10+1の計算結果が出力される #メソッド内にputsを定義しない理由は文字列ではないから出力結果
$ ruby method_add.rb 11戻り値
メソッドからメソッドの呼び出し元に戻す値のこと他のプログラミング言語で戻り値を明示的に表す場合があるがrubyの場合は不要
method_add.rbdef add(x, y) return x + y end puts add(10,1)$ ruby method_add.rb 11 #エラーにはならないメソッドの命名規則
メソッド名は小文字
method_name.rbdef hello puts "Hello" end hello出力結果
$ ruby method_name.rb Hello2語以上のメソッド名になる場合はスネークケース(アンダースコア)でつなぐ
※アンダースコアで始まるメソッド名はエラーにはならないが意図がない限り避けるmethod_name.rbdef hello_world puts "Hello" end hello_world出力結果
$ ruby method_name.rb Helloメソッド名に数字は使用可能。ただし、使用しない方が良い
製作者しかわからないマジックナンバーになるためmethod_name.rbdef hello1 puts "Hello" end hello1 #行頭に数字を持ってくるとエラーになる def 1hello puts "Hello" end 1hello出力結果
$ ruby method_name.rb Hello $ ruby method_name.rb method_name.rb:1: syntax error, unexpected tINTEGER def 1hello ^実践
引数にcatが渡されたら"meow"
引数にdogが渡されたら"bowwow"
それ以外なら"???と出力されるメソッドanimal_cry.rbdef cry(animal) if animal == "cat" puts "meow" elsif animal == "dog" puts "bowwow" else puts "???" end end puts cry(引数) #戻り値の出力出力結果
$ ruby animal_cry.rb meow #cat $ ruby animal_cry.rb bowwow #dog $ ruby animal_cry.rb ??? #それ以外FizzBuzzメソッド
3で割り切れる時Fizz
5で割り切れる時Buzz
15で割り切れる時FizzBuzz
それ以外は数値を文字列にして返すfizz_buzz.rbdef fizz_buzz(n) if n % 15 == 0 "FizzBuzz" elsif n % 3 == 0 "Fizz" elsif n % 5 == 0 "Buzz" else n.to_s end end puts fizz_buzz(1) puts fizz_buzz(2) puts fizz_buzz(3) puts fizz_buzz(4) puts fizz_buzz(5) puts fizz_buzz(6) puts fizz_buzz(7) puts fizz_buzz(8) puts fizz_buzz(9) puts fizz_buzz(10) puts fizz_buzz(11) puts fizz_buzz(12) puts fizz_buzz(13) puts fizz_buzz(14) puts fizz_buzz(15)出力結果
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzzポイントは3で割る処理の一番最初に持ってきてしまうと、
15で割る時にFizzが返ってしまうので、15で割る処理を一番最初に持ってくること。
- 投稿日:2019-03-01T01:02:04+09:00
Amazon Linux 2にrbenvをいれる
手順
# rbenvをインストール # 参考: https://github.com/rbenv/rbenv#basic-github-checkout git clone https://github.com/rbenv/rbenv.git ~/.rbenv echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile echo 'eval "$(rbenv init -)"' >> ~/.bash_profile source ~/.bash_profile # ruby-buildをインストール # 参考: https://github.com/rbenv/ruby-build#readme mkdir -p "$(rbenv root)"/plugins git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
- 投稿日:2019-03-01T00:45:20+09:00
undefined method `each' forエラー 備忘録
<% post.each do |p| %>
<%= p.text %>
みたいな感じでeach文を回して要素を一つずつ表示した際に
undefined method `each' for というエラーが発生エラーの原因
post.eachのpostにpostオブジェクトが渡されていたこと
eachは配列の要素の数だけブロックを繰り返し実行する
すなわち、postオブジェクトの配列を渡してあげれば解決
流れ
posts_contorller.rb@post = Post.find(params[:id])パラメーターで送られてきたpostをfindで取り出して@postへ代入
qiita.rb<%= render partial: 'posts/post', locals: { post: @post } %>@postを部分テンプレート先でpostというローカル変数で使用
qiita.rb<% post.each do |p| %>postをpへ代入して要素の数だけ表示
修正部分
before
posts_contorller.rb@post = Post.find(params[:id])findメソッドは条件に合致するオブジェクトを取り出す
after
posts_contorller.rb@post = Post.where(id: params[:id])whereメソッドは条件に合致するオブジェクトを配列として取り出す
要するにeachには配列を渡しましょうということです
参考





