20200619のRubyに関する記事は13件です。

【Rails】ancestryを用いた多階層カテゴリー機能の実装『seed編』

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

投稿機能実装
多対多のカテゴリー機能実装
多階層カテゴリー機能実装(準備編)

実装

id name ancestry
1 ビジネス nil
2 金融 1
3 1/2
4 為替 1/2
5 税金 1/2
6 経済 2
7 日本経済 1/6
8 国際経済 1/6
9 経営 3
10 経営学 1/9
11 戦略・攻略 1/9
12 企業・開業 1/9
13 マーケティング 4
14 経営学 1/13
15 戦略・攻略 1/13
16 企業・開業 1/13

本のカテゴリーに上記の様な親子関係を持たせたい場合は、以下の様にデータを作成します。

seed.rb
business = Category.create(name: 'ビジネス')
business_child_array = ['金融', '経済', '経営', 'マーケティング']
business_grandchild_array = [
  ['株', '為替', '税金'], # 金融の子
  ['日本経済', '国際経済'], # 経済の子
  ['経営学', '戦略・管理', '起業・開業'], # 経営の子
  ['広告', '営業', '開発'] # マーケティングの子
]

business_child_array.each_with_index do |child, i|
  child = business.children.create(name: child)
  business_grandchild_array[i].each do |grandchild|
    child.children.create(name: grandchild)
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 値を正規化する

値の正規化

ある規則に従うように情報を変換することを正規かと言います。
今回はフリガナとして入力された値が平仮名だった場合に正規化して
カタカナにするという正規化を行ってみます。

まずapp/models/concernsディレクトリにnormalizerを作成していきます。

string_normalizer.rb
require "nkf"

module StringNormalizer
  def normalize_as_furigana(text)
    NKF.nkf("-W -w -Z1 --katakana", text).strip if text
end

以下のコードが実際に正規化を行っています。

NKF.nkf("-W -w -Z1 --katakana", text).strip if text

指定される引数は以下のような意味です。

NKF#nkfメソッドの引数

フラグ 意味
-W 入力の文字コードがUTF-8
-w UTF-8で出力
-Z1 全角の英数字、記号、半角スペースを半角に変える
--katakana ひらがなをカタカナに変換

これで準備ができました。あとはモデル側でモジュールを組み込みましょう

model.rb
class UserController < ApplicationRecord
  include StringNormalizer

  before_validation do
    self.name_kana = normalize_as_furigana(name_kana)
  end

こんな感じでバリデーションを通す前にname_kanaで指定された属性を
ひらがな-> カタカナへ正規化することができました。

本日は以上です!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ancestryを用いた多階層カテゴリー機能の実装『準備編』

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

投稿機能実装
多対多のカテゴリー機能実装

実装

1.Gemを導入

Gemfile
# 追記
gem 'ancestry'
ターミナル
$ bundle

2.カラムを追加

データ量がかなり多くなるのでindexを張ります。

ターミナル
$ rails g migration AddAncestryToCategory ancestry:string:index
ターミナル
$ rails db:migrate
schema.rb
create_table "categories", force: :cascade do |t|
  t.string "name"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.string "ancestry"
  t.index ["ancestry"], name: "index_categories_on_ancestry"
end

3.モデルを編集

category.rb
# 追記
has_ancestry

has_ancestry
➡︎ ancestryを使える様になる。

メソッド一覧

メソッド名 返り値
parent 親レコードを取得
parent_id 親レコードのIDを取得
root レコードのルートを取得
root_id レコードのルートIDを取得
root?is_root? レコードがルートであれば、trueを返す
ancestors ルートで始まり、親で終わる、レコードの祖先を返す
ancestors? レコードに祖先(ルートノードではない)がある場合はtrueを返す
ancestor_ids レコードの祖先のIDを返す
path ルートで始まり、自己で終わる、レコードのパスを返す
path_ids ルートIDで始まり、 自己のIDで終わるパスのIDをリストで返す
children 子レコードを取得
child_ids 子レコードのIDを取得
has_parent?ancestors? レコードが親を持っていれば、trueを返す
has_children?children? レコードが子を持っていれば、trueを返す
is_childless?childless? レコードが子を持っていなければ、trueを返す
siblings 兄弟レコード(同じ階層のレコード)を返す
sibling_ids 兄弟レコード(同じ階層のレコード)のIDを返す
has_siblings?siblings? レコードの親に複数の子がある場合はtrueを返す
is_only_child?only_child? レコードが親の唯一の子である場合はtrueを返す
descendants 子レコード、孫レコード、曽孫レコード... を返す
descendant_ids 子レコード、孫レコード、曽孫レコード... のIDを返す
indirects 孫レコード以下を返す
indirect_ids 孫レコード以下のIDを返す
subtree 子孫と自己のモデルを返す
subtree_ids レコードのサブツリーのIDをリストで返す
depth ノードの深さを返す
parent_of?(node) このレコードを(node)の親にする
root_of?(node) このレコードを(node)のルートにする
ancestor_of?(node) (node)の祖先にはこのレコードが含まれる
child_of?(node) (node)はレコードの親
descendant_of?(node) (node)はこのレコードの祖先の1つ
indirect_of?(node) (node)はこのレコードの祖先の1つですが、親ではない

階層構造

親:ビジネス
子:経済
孫:日本経済、国際経済

本のカテゴリーに上記の様な親子関係を持たせたい場合は、以下の様にデータを作成します。

business = Category.create(name: 'ビジネス')

business_economy = business.children.create(name: '経済')

business_economy.children.create([{ name: '日本経済' }, { name: '国際経済' }])

カラム構造

id name ancestry
1 ビジネス nil
2 経済 1(親のid)
3 日本経済 1/2(親のid/子のid)
4 国際経済 1/2(親のid/子のid)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【enum】 rails enumを利用してデータの可読性をあげよう

【ゴール】

rails においてenumの使用

画面収録 2020-06-19 19.28.08.mov.gif

【メリット】

■ dbの可読性向上、管理しやすい
■ 日本語化にも応用が効く

【開発環境】

■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7

【実装】

と言ってもとても簡単!!!!対象のモデルに追記するのみ

※①が一番簡単な書き方
※②だと日本語も可能

model/hoge.rb
 enum カラム名:[:任意の単語, :任意の単語, :任意の単語, :任意の単語]
 enum カラム名:{"任意の単語": 1,"任意の単語": 2.......}

※number_field をselectに変更する
※enumで設定した値を取得して、選択できるようになります。

hoge/_form.html.erb
<%= form.select :カラム名, モデル名.カラム名s.keys, :selected=>モデル名.カラム名s[カラム名] %>

以上

【合わせて読みたい】

■enumについて
https://web-camp.io/magazine/archives/16862

■form_withについて
https://qiita.com/tanaka-yu3/items/50f54f5d4f4b8dfe19f3

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コードの命名を文系の観点から考察

はじめに

Rubyで書いている時のコードの規約の経験まとめとして書いてます。

読み易いコードの定義

読んだ人が変更を加えたりバグを発見することができるようになるレベルで最短でコードを読み終えることができるということを目標にしてコードを書かなければならない

変数もメソッドもクラスも何を司っているのかを直訳した時に分かるようなっていること

表面上の改善として、任意に書けるものへの理解のしやすさを考える

 変数、メソッド、クラス、凡そ任意で書き、定義することができるこれらのコードの部分はよく考えて書かないと、前述のコード定義をクリアすることは至難である。正直、こちらが意図して書いていたとしても誤解を招くことすらある。誤読される可能性を出来る限り排除しないと、こっちが何も考えてないように思われるから腹立たしいものです。

明確な単語を使用する

 簡単な動詞、名詞、形容詞、前置詞を使用する。
 英単語を使用する上で、カチコチの英文法に則って書く必要はなく、むしろそれが混乱させることを招くこともあるので、その辺はプロダクトやチーム内のルールとして納得するような状況判断も必要になってくる。
 例えば、of。A of Bの訳詞方は、BのA単体ではなく、AのBと言う使い方も存在する。どちらを使っても問題無いような時でもBのAに慣れ親しんでいる人が多い場合、警告されたりします。

 多分、名詞として使われることが有名でも形容詞としても使える単語があったとして、使用すればそれも警告対象になりそう。例えば、product costとか。要は、見慣れてるか見慣れていないかと言うすごい経験的なものに依存しています。

 過去分詞も過去形の動詞と混同されるので避けた方がいい。
 文章読解における厄介な分詞もまた文脈依存で判断する必要があることがあるので、表現としては避けるべきであろう。およそ文脈判断を要求される文法は使用しない方がいいと思われる。関係代名詞は流石に長くなる文法なので、使用されることは無いだろうが、それぞれの文法が折り重なった場合の判断する術は数多くあるが、なるべく短く情報を入れ込む必要のある表現を余儀なくされるコーディングにおいて、文脈で委ねる表現はどれも避ける必要があると思われる。

意識すべき文法は多く無い

  • 動詞を使用する時は5文型を意識する必要があるので、自動詞と他動詞の使い分けは意識する。
  • 複数形と単数系

今のところ、気にするのはこれくらいですね。

自明の言葉は不要

 例えば、registered userと言う変数名はuserで良い。DBに入ってきている時点で登録されていることは明白だからである。

汎用的な名前を避け、具体的な名付けを行う

 名詞単発で変数を作ると、コードが増えてきた時に読み手の誤解を招くことになる。例えば、あちこちにdataとしかない変数があると、読み辛さを増す。

略記は避ける

 これは納得。流石にget_user_dataをgudとかにされたら分からん・・・

メソッドは動詞を使用

 処理を行うコードなので、動詞を使うのがベスト。

クラス名や変数は名詞を使用

 何を司っているクラスなのか、何が格納されている変数なのかを意識する

言い換え表現は使用しない

 コードは文章では無いので、言い換え表現はしない方がいい。なんとなく文章書く感覚でやってるとやっちゃいがち。
 Memmber = userなどのように殆ど同じ意味を持つものを使って表現することはせず、同じ意味の持つものは同一の単語で統一する。

非推奨な記法

 ハンガリアン記法と呼ばれる型やスコープなどの情報を変数名やクラス名に入れ込む命名法、現在非推奨であり、多くの場合のアンチパターンとなるらしいです。
 例えば、配列であれば、arr_dataとかにして変数にするなどは避けるべきである。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyでトリボナッチ数列の問題を解いてみた(制限時間10分)

はじめに

低学歴の筆者がトリボナッチ数列の問題を10分以内で解決しなければならない状況に陥り、トリボナッチという言葉を忘れてしまった状態(記憶喪失状態)から10分以内でrubyで解決した体験記でございます。
数学に自信がある人・ない人も力試しに10分以内で実施してみてはどうでしょうか?

問題

問1
1,3,7,11,21,39...
50番個目にある数字は何ですか?

という問題を解決しなければいけない状況になりました...

...(;゚д゚)ゴクリ

10秒くらい意識を失いましたが、とりあえず現状を理解せねば!!と気合を入れ直しました。

トリボナッチ数列について

トリボナッチ数列とは、項の数字がその前の3つの項の数字の合計となっている数列である...らしいです
中学入試で勉強するらしいが、昨日何食べたっけ?レベルのメモリーしかない私の記憶喪失は治りませんでした(...現在30歳)

検索した結果...

トリボナッチ数とは、
...中略
a[0]=a[1]=0
a[2]=1
a[n]=a[n-1]+a[n-2]+a[n-3]
と定義された数列
この数列の一般項を求める。
f(z)=Σ[n=0→∞]a[n]zⁿ
=a[0]+a[1]z+Σ[n=2→∞]a[n]zⁿ
=Σ[n=2→∞]a[n]zⁿ
=a[2]z²+Σ[n=3→∞]a[n]zⁿ
=z²+Σ[n=3→∞]{a[n-1]+a[n-2]+a[n-3]}zⁿ
=z²+Σ[n=3→∞]{a[n-1]}zⁿ+Σ[n=3→∞]{a[n-2]}zⁿ+Σ[n=3→∞]{a[n-3]}zⁿ
=z²+zΣ[n=3→∞]{a[n-1]}z^(n-1)+z²Σ[n=3→∞]{a[n-2]}z^(n-2)+z³Σ[n=3→∞]{a[n-3]}z^(n-3)
=z²+zΣ[n=2→∞]a[n]zⁿ+z²Σ[n=1→∞]a[n]zⁿ+z³Σ[n=0→∞]a[n]zⁿ...以下略

いや10分じゃ理解できねーよ!!
理解することは諦めて、筆者的解釈のもとrubyで表現しました。

筆者的解釈

1個目 + 2個目 + 3個目 = 4個目
2個目 + 3個目 + 4個目 = 5個目の繰り返し
ところてん方式的なやつか ← 全然違う

1個目をaとし、2個目をb、3個目をcと表現し合計である4個目をdと表現
足した後、bがaになりcがb、dがcになると考えそれぞれを代入し、それを47回繰り返す!!
※ 47としているのは最初に3個の値を代入しているため50から3を引いた47としています。

tribonacci.rb
a = 1
b = 3
c = 7
n = 0
while n < 47
  d = a + b + c
  a = b
  b = c
  c = d
  n += 1
end

puts c

最後のcが47個目の数字になる!!

これだ!!

この考えをもう少し丁寧に表現して...

tribonacci.rb
puts "求めたい数字を入力して下さい"
puts "1つ目の数字"
a = gets.to_i
puts "2つ目の数字"
b = gets.to_i
puts "3つ目の数字"
c = gets.to_i
puts "何番目の数字を求めますか?"
t = gets.to_i

n = 0
while n < (t - 3)
  d = a + b + c
  a = b
  b = c
  c = d
  n += 1
end

puts "#{t}番目の数は#{c}です"

これで50個目の数字17079382868243を求めることができました!!
正確な時間は測ってませんが、なんとか10分以内で実装しました。

おわりに

もっと良い計算方法があると思いますが、低学歴の私には10分以内で表現するのはこれぐらいが限界でした。
皆様はどうでしたか?10分以内って結構焦りますよね?
Wikipediaで5行くらいで書いてるコードもあったのでもっと簡単にかけるはずですが、時間制限にテンパってしまってこんなコードになってしまいました...
エンジニアになるためには、コードを書くだけでなく数学の勉強もしなければならないと今回の件で痛感しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vagrant コマンドがなんだか動かない時

vagrant コマンドがよくわからないエラーに悩まされるときがある。

そんな時は、xcodeのバージョンアップが影響している事がしばしば。

一旦以下のコマンドを実行して試してみる事をオススメする。

$ xcode-select --install
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

大好きなSCANDALのLINEbotを作りたいの巻1

作りたいbot

毎日決まった時間にランダムでSCANDALのMVを送るbot
※SCANDALは女性バンドです。

そのための僕の頭の中の構想(railsで作成)

  1. まずはWEB上で動く物を作る
  2. それをLINEbotにする
  3. そこから機能を追加していく(例えば、ACIDMANとLINEで送るとACIDMANの曲をランダムに返すなど) ※ACIDMANもバンドです。

ひとまずできたこと

  1. まずはWEB上で動く物を作る

参考にした記事

Qiitaの記事を元にYouTube Data APIのリファレンスを参考にしました。

Qiita
https://qiita.com/sakakinn/items/46c0d4945e4646f346f6

YouTube Data API
https://developers.google.com/youtube/v3/docs?hl=ja

コード

index.html.erb
<% number = 0 %>
<% ran = rand(1..11) %>
<% @youtube_data.items.each do |item| %>
  <% number = number + 1 %>
  <% if number == ran %>
   <% snippet = item.snippet %>
   <p><%= snippet.title %></p>
   <p><%= snippet.published_at %><%= snippet.channel_title %></p>
   <div><iframe width="560" height="315" src="https://www.youtube.com/embed/<%= item.id.video_id %>" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
  <% end %>
<% end %>
youtube_controller.rb
class YoutubeController < ApplicationController
  def find_videos(keyword)
    service = Google::Apis::YoutubeV3::YouTubeService.new
    service.key = ENV["YOUTUBEKEY"]

    next_page_token = nil
    opt = {
      q: keyword,
      type: 'video',
      channel_id: 'UCSNX8VGaawLFG_bAZuMyQ3Q',
      max_results: 11,
      order: :date,
      page_token: next_page_token
    }
    service.list_searches(:snippet, opt)
  end

  def index
    @youtube_data = find_videos('SCANDAL')
  end
end

出力結果↓
https://twitter.com/pompom06yutoz/status/1273869183491559425?s=21

今わかっている課題

1. Viewで11個のデータにアクセスしているので、それを無くしてランダムにチャンネルからデータを一つだけ取り出したい。(助けてくれ〜ww)
2. 今のままだとチャンネルが固定(いったんスルーで)

次にすること

とりあえずこれをLINEbotにしてみて、課題が浮上したらその時に考える。

最後に

プログラミング学習始めて約4ヶ月が経過し、今程よく楽しんでいる人間です。
もし、何か良い代替の案があったら気軽にコメントお願いします〜。
後、SCANDALが好きな人もぜひ。
つづく

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[備忘録] [初心者] Rubyの書き方メモ(リファクタリング) 1

概要

前回の投稿で掲載していたRubyのコードがRubyらしい書き方になっていないことに気づいたので、修正も兼ねて勉強のメモを残します。

下記記事を拝見したのがきっかけで、勉強のために実際に内容を参考にさせて頂きながら前回投稿分のコードを例にして修正してみました。
[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか | Qiita

コード

修正前

Upcasing.rb
def Upcasing(result_lines)
  result_lines[0] = result_lines[0].capitalize
  break_flg = false
  ## ④ Rubyでのハッシュの記法 (修正せず:できなかった理由は後述)
  break_sign = { "."=>true, "!"=>true, "?"=>true, ","=>false }

  result_lines.each_index do |i|
    ## ① 条件分岐と真偽値
    if break_flg == true
      result_lines[i] = result_lines[i].capitalize
    end

    ## ② 配列要素の指定方法、文字列中の指定番の文字の参照
    if break_sign[result_lines[i].slice(-1)] == true
      break_flg = true
    else
      break_flg = false
    end
  end
  joined_line = result_lines.join(" ")
  ## ③ Rubyでの戻り値の表記
  return joined_line
end

print Upcasing(["oh,", "yeah!", "hello!"])

## 実行結果
## Oh, yeah! Hello!

変更点

def Upcasing(result_lines)
  result_lines[0] = result_lines[0].capitalize
  break_flg = false
  ## ④ Rubyでのハッシュの記法 (修正せず、変更できなかった理由は後述)
  break_sign = { "."=>true, "!"=>true, "?"=>true, ","=>false }

  result_lines.each_index do |i|
    ## ① 条件分岐と真偽値
-   if break_flg == true
+   if break_flg
      result_lines[i] = result_lines[i].capitalize
    end

    ## ② 配列要素の指定方法、文字列中の指定番の文字の参照
-   if break_sign[result_lines[i].slice(-1)] == true
+   if break_sign[result_lines[i][-1]]   
      break_flg = true
    else
      break_flg = false
    end
  end
  joined_line = result_lines.join(" ")
  ## ③ Rubyでの戻り値の表記
- return joined_line
end

print Upcasing(["oh,", "yeah!", "hello!"])

修正後

Upcasing.rb
def Upcasing(result_lines)
  result_lines[0] = result_lines[0].capitalize
  break_flg = false
  break_sign = { "."=>true, "!"=>true, "?"=>true, ","=>false }

  result_lines.each_index do |i|
    if break_flg
      result_lines[i] = result_lines[i].capitalize
    end

    if break_sign[result_lines[i][-1]]
      break_flg = true
    else
      break_flg = false
    end
  end
  joined_line = result_lines.join(" ")
end

print Upcasing(["oh,", "yeah!", "hello!"])

## 実行結果
## Oh, yeah! Hello!

各修正箇所の詳細

検討箇所①〜④について、番号順に追っていきます。

① 条件分岐と真偽値

-   if break_flg == true
+   if break_flg

制御構造 > if | Ruby 2.7.0 リファレンスマニュアル

恥ずかしいことですが、惰性で使いすぎていて、式として変数単体を記載するとその真偽を返すという根本的な仕様を理解していませんでした。Rubyに限った話ですらないですね・・・。
少なくとも、Rubyでは単純な真偽判定で(== true)を書かないようにします。

Ruby
hoge = true
p hoge
if hoge; hoge = false; end
p hoge

# true
# false
JavaScript
var hoge = true;
console.log(hoge);
if (hoge) hoge = false;
console.log(hoge);

// true
// false
C#
public class Hello{
  public static void Main(){
    bool hoge = true;
    System.Console.WriteLine(hoge);
    if (hoge){ hoge = false; }
    System.Console.WriteLine(hoge);
  }
}

// True
// False

② 配列要素の指定方法、文字列中の指定番の文字の参照

-   if break_sign[result_lines[i].slice(-1)] == true
+   if break_sign[result_lines[i][-1]]

③ Rubyでの戻り値の表記

def Upcasing(result_lines)
  ##
  ## コード省略
  ##
  joined_line = result_lines.join(" ")
- return joined_line
end

④ Rubyでのハッシュの記法

break_sign = { "."=>true, "!"=>true, "?"=>true, ","=>false }

初めは、下記のようにシンボルを用いた記法に修正しようとしました。

修正案
break_sign = { ".": true, "!": true, "?": true, ",": false }

上記のように変更すると、上位のメソッドのデバッグ結果が変わってしまいました。
そこで、ハッシュの中身を確認すると、以下のように格納されるキー"!"が文字列では無くなっていました。

break_sign = { "."=>true, "!"=>true, "?"=>true, ","=>false }
p break_sign
#=> {"."=>true, "!"=>true, "?"=>true, ","=>false}

break_sign = { ".": true, "!": true, "?": true, ",": false }
p break_sign
#=>{:"."=>true, :!=>true, :"?"=>true, :","=>false}

どうにかシンボルを使って表現しようとも考えたのですが、そもそもハッシュのキーに特殊文字一文字を当てる場面がそんなにあるのだろうかと疑問に思い、今回はスルーすることにしました。
この件に関して、また気づきがあれば別途投稿します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS☆☆☆ デプロイまでの道のり3(短いバージョン、全5回)

1)背景

第3回目です。自身のポートフォリオをデプロイするために、いよいよunicornを介してrailsを起動します。
AWS関連手順記事はすごく多いので、ここでは備忘録も含めて、非常に端的に手順を記載します。
全5話で進めます。

2)環境

項目 内容
OS.Amazon Linux AMI release 2018.03
Ruby v2.5.1
Ruby On Rails v5.2.4.3
MySQL v5.6
Unicorn v5.4.1

3)内容

以下設定で75分程度かなと思います。(段取りが分かっていれば、30分)
※【ローカルマシン】指定以外は、全てAWSでの作業になります。

(1)【ローカルマシン】Unicornの設定(20分)

  • Gemfileにunicornを記述
  • bundle installの実行(ユニコーン導入)
  • 作成された設定ファイル(unicorn.rb)の編集

(2)Gitのクローニング(15分)

  • 格納フォルダの配置と権限付与
  • Gitからのクローニング(※)
  • AWSのswap領域作成(別記事をご参照ください)

※クローニングする際には以下が必要です。
 (1)先ほどのローカルunicorn設定がpushされていること
 (2)最新master化
 (3)本番環境(production)のDBユーザ設定 

(3)本番デプロイ設定(30分)

  • bundlerのインストール
  • bundle installの実行(時間がかかります。)
  • 秘密鍵の取得
  • 環境変数にdbユーザパスワード(productionと合わせる)と秘密鍵を設定する
  • DB-CreateとDB-Migrateの実行
  • assetsディレクトリのプレコンパイル

(4)本番Rails起動(10分)

  • インスタンスの3000番ポート開放
  • unicornを介してサービスの起動

ここまで完了したら、「http://ElasticIP:3000」にアクセスすると、アプリケーションのトップページに遷移するはずです。

以上、短く記載しました。
ここまで、全てストレートに行ったわけではなく、エラーも出力されました。この辺りは、環境や設定により様々ですので、別記事にてエラー対策を掲載したいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FinderのデフォルトテキストエディタをAtomに変更する方法

システム環境設定からデフォルトテキストエディタを変更出来なかったのでやり方を調べてみました。

手順

1.Finderから適当なテキストファイルを右クリックし「情報を見る」を選択
2.▼このアプリケーションから設定したいテキストエディタを選択(今回はAtom)
3.その下の「全てを変更」で設定完了

3を飛ばせばファイルごとにエディタを選択できるみたいですね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails アソシエーションでモデル間に1対多の関係性を持たせる

はじめに

Rails初学者の私がアソシエーションによってテーブルを関連付けた後、
アクションメソッドへパラメーターを受け渡せずに非常に苦労したので記事にしてみます。
ゴールはPlace(カフェ)にメニュー(menus)の情報を持たせて画面上に出力することです。

※初投稿のため理解しがたい部分、間違っている部分等あるかもしれません。
なるべく正しい情報を記述したいと努力していますがご了承いただければと思います。
コメントでご意見等いただけましたら嬉しいです!

ひとまずPlaceとMenuのカラムを確認

irb(main):005:0> Place.column_names
=> ["id", "name", "message", "created_at", "updated_at", "user_id"]
irb(main):006:0> Menu.column_names
=> ["id", "title", "price", "message", "created_at", "updated_at", "place_id"]

上記の通りとなります。

ログインしているUserがお気に入りのカフェを投稿→そのカフェに対してメニューの情報も追加することができる。
という機能です。

アソシエーションによるテーブルの結合

app/models/place.rb
class Place < ApplicationRecord
  belongs_to :user
  has_many :menus
end

Railsでは命名規則が重要なのでこの単数形と複数形の記述を間違えないように注意。
(1人の)userに対して(1つの)place、(1つの)placeに対して(複数の)menusを持ちます。

belongs_to (〜に属する) has_many (たくさん持っている)・・・わかりやすいですね!

app/models/menu.rb
class Menu < ApplicationRecord
  belongs_to :place
end

menu.rbの方はこんな感じ。

とりあえずこれでテーブル間の紐付けは完了しました。

places_controller.rb
    [1] pry(#<PlacesController>)> @place
=> #<Place:0x00007f9d1e88cc10
 id: 3,
 name: "hoge Coffee",
 message: "自宅から最寄りのカフェで落ち着いた雰囲気がとても素敵です。",
 created_at: Thu, 18 Jun 2020 00:05:20 UTC +00:00,
 updated_at: Thu, 18 Jun 2020 13:14:42 UTC +00:00,
 user_id: 1>
[2] pry(#<PlacesController>)> params
=> <ActionController::Parameters {"controller"=>"places", "action"=>"show", "id"=>"3"} permitted: false>

views/places/show.html.erbからメニューの登録を行いたいのでパラメーターを確認します。
こちらが今回メニューを登録したいカフェの情報になります。

places/show.html.erb
  <%= link_to 'メニューを登録', new_menu_path(id: @place.id) %>

メニューの登録をするためにmenus_controllerのnewアクションへ。

この時に_pathヘルパーへ引数を渡しておかないとmenus_controllerのnewアクションでplaceを検索できません。

menus_controller.rb
class MenusController < ApplicationController

  def new
    @menu = Menu.new
    @place = Place.find_by(id: params[:id])
  end
()

入力フォーム↓

menus/new.html.erb
<%= form_with model:@menu, local: true do |f| %>
<h2>メニューを登録</h2>
<p>料理の名前 : <%= f.text_field :title %></p>
<p>Price : <%= f.text_field :price %></p>
<%= f.hidden_field :place_id, :value => @place.id %>
<%= f.submit '登録する' %>
<% end %>

place_idは入力するようなものではないのでhidden_fieldで渡された値を受け取りしてあげます。

createアクションでのplace_idを受け取り方ですがメニューを登録する際の入力フォームで受け取ります。

menus_controller.rb
def create
    # 入力フォームで受けとったパラメーターをここで受け取る
    @menu = Menu.create(
      title: menus_params[:title],
      price: menus_params[:price],
      place_id: menus_params[:place_id]
    )
    # ここでちゃんと受け取れているか確認入れてみます
    binding.pry
end

(中略)

private

  def menus_params
    params.require(:menu).permit(:title, :price, :place_id)
  end

()

確認のためフォームに入力してみます。
結果・・・

[1] pry(#<MenusController>)> menus_params
=> <ActionController::Parameters {"title"=>"アイスコーヒー", "price"=>"280", "place_id"=>"3"} permitted: true>

ちゃんとplace_idを受け取ることができました。

これでちゃんと1対多の関係性(placeに対してmenus)を持ったパラメーターの受け取りができます。

    <% @place.menus.each do |menu| %>
        <p><%= menu.title %> <%= menu.price %></p> 
    <% end %>

登録したメニューはこんな感じで出力できます。

[1] pry(#<PlacesController>)> @place.menus
  ()
=> [#<Menu:0x00007ffda376a4c8
  id: 37,
  title: "チョコレートケーキ",
  price: 250,
  created_at: Thu, 18 Jun 2020 01:36:00 UTC +00:00,
  updated_at: Thu, 18 Jun 2020 01:36:00 UTC +00:00,
  place_id: 3>,
 #<Menu:0x00007ffda3773eb0
  id: 44,
  title: "アイスコーヒー",
  price: 280,
  created_at: Fri, 19 Jun 2020 00:24:50 UTC +00:00,
  updated_at: Fri, 19 Jun 2020 00:24:50 UTC +00:00,
  place_id: 3>]

アソシエーションで紐付けされているので@place.menusで登録したメニューを確認できます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby 2.7.1 で解く AtCoder ABC127 D ハッシュ

はじめに

AtCoder の過去問題の環境がバージョンアップされました。

今回のお題

AtCoder Beginner Contest D - Integer Cards
Difficulty: 891

今回のテーマ、ハッシュ

問題からは優先度付きキューなのですが、制約が緩いようでソートでも解けます。

解法1 ハッシュ(2.7.1)

ruby.rb
n, m = gets.split.map(&:to_i)
h = gets.split.map(&:to_i).tally
m.times do
  b, c = gets.split.map(&:to_i)
  if h.key?(c)
    h[c] += b
  else
    h[c] = b
  end
end
ans = 0
cnt = 0
h.sort{_2 <=> _1}.each do |k, v|
  if cnt + v < n
    ans += k * v
    cnt += v
  else
    ans += k * (n - cnt)
    break
  end
end
puts ans
tally.rb
h = gets.split.map(&:to_i).tally

tallyで配列からハッシュを生成しています。

numberedparameter.rb
h.sort{_2 <=> _1}.each do |k, v|       # after 2.7.1

h.sort{|a, b| b <=> a}.each do |k, v|  # before

ブロック内のパラメータを番号で指定することができます。
sort_byの記述方法は不明です。

解法2 ハッシュ

ruby.rb
n, m = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
h = Hash.new(0)
a.each do |x|
  h[x] += 1
end
m.times do
  b, c = gets.split.map(&:to_i)
  h[c] += b
end
ans = 0
cnt = 0
h.sort_by{|k, v| -k}.each do |k, v|
  if cnt + v < n
    ans += k * v
    cnt += v
  else
    ans += k * (n - cnt)
    break
  end
end
puts ans

2.3.3でも通る書き方です。

解法3 配列

ruby.rb
n, m = gets.split.map(&:to_i)
a = gets.split.map(&:to_i).sort
h = []
m.times do
  h << gets.split.map(&:to_i)
end
i = 0
h.sort_by{|u, v| -v}.each do |x, y|
  break if a[i] >= y
  x.times do
    a[i] = y
    i += 1
    break if i >= n
    break if a[i] >= y
  end
  break if i >= n
end
puts a.inject(:+)

5月頃に通したものです。
これを今回通しますと若干速くなっているようです。

2.3.3 2.7.1
実行時間 (ms) 296 230

解法4 優先度付きキュー

ruby.rb
class Heap
  attr_reader :size
  def initialize(up: false)
    @up = up
    @heap = []
    @size = 0
  end
  def sum
    x = 0
    @size.times do |i|
      x += @heap[i]
    end
    x
  end
  def push(n)
    n = -n if @up
    i = @size
    while i > 0
      pid = (i - 1) / 2
      break if n >= @heap[pid]
      @heap[i] = @heap[pid]
      i = pid
    end
    @heap[i] = n
    @size += 1
  end
  def pop
    return nil if @size == 0
    top = @heap[0]
    @size -= 1
    n = @heap[@size]
    i = 0
    while i * 2 + 1 < @size
      cid1 = i * 2 + 1
      cid2 = cid1 + 1
      if cid2 < @size && @heap[cid2] < @heap[cid1]
        cid1 = cid2
      end
      break if @heap[cid1] >= n
      @heap[i] = @heap[cid1]
      i = cid1
    end
    @heap[i] = n
    if @up
      -top
    else
      top
    end
  end
end

_, m = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
b = Array.new(m){gets.split.map(&:to_i)}
h = Heap.new(up: false)
a.each do |x|
  h.push(x)
end
f = false
b.sort_by{|x, y| -y}.each do |x, y|
  x.times do
    u = h.pop
    if y > u
      h.push(y)
    else
      h.push(u)
      f = true
    end
    break if f
  end
  break if f
end
puts h.sum

ヒープの最小値を取り出して、比較して戻します。

_1 _2 _3 _4
コード長 (Byte) 342 342 319 1236
実行時間 (ms) 822 288 296 773
メモリ (KB) 34416 39264 21776 20824

番号指定パラメータ(numbered parameter)が便利そうです。

まとめ

  • ABC 127 D を解いた
  • Ruby に詳しくなった

参照したサイト
サンプルコードでわかる!Ruby 2.7の主な新機能と変更点 Part 1 - 番号指定パラメータ(numbered parameter

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む