- 投稿日:2020-06-19T20:59:39+09:00
【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.rbbusiness = 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
- 投稿日:2020-06-19T20:36:44+09:00
Rails 値を正規化する
値の正規化
ある規則に従うように情報を変換することを正規かと言います。
今回はフリガナとして入力された値が平仮名だった場合に正規化して
カタカナにするという正規化を行ってみます。まずapp/models/concernsディレクトリにnormalizerを作成していきます。
string_normalizer.rbrequire "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.rbclass UserController < ApplicationRecord include StringNormalizer before_validation do self.name_kana = normalize_as_furigana(name_kana) endこんな感じでバリデーションを通す前にname_kanaで指定された属性を
ひらがな-> カタカナへ正規化することができました。本日は以上です!!
- 投稿日:2020-06-19T20:20:45+09:00
【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'ターミナル$ bundle2.カラムを追加
データ量がかなり多くなるので
indexを張ります。ターミナル$ rails g migration AddAncestryToCategory ancestry:string:indexターミナル$ rails db:migrateschema.rbcreate_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" end3.モデルを編集
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)
- 投稿日:2020-06-19T19:37:19+09:00
【enum】 rails enumを利用してデータの可読性をあげよう
【ゴール】
rails においてenumの使用
【メリット】
■ 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
- 投稿日:2020-06-19T18:12:51+09:00
コードの命名を文系の観点から考察
はじめに
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とかにして変数にするなどは避けるべきである。
- 投稿日:2020-06-19T16:12:29+09:00
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.rba = 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.rbputs "求めたい数字を入力して下さい" 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行くらいで書いてるコードもあったのでもっと簡単にかけるはずですが、時間制限にテンパってしまってこんなコードになってしまいました...
エンジニアになるためには、コードを書くだけでなく数学の勉強もしなければならないと今回の件で痛感しました。
- 投稿日:2020-06-19T16:11:44+09:00
vagrant コマンドがなんだか動かない時
vagrant コマンドがよくわからないエラーに悩まされるときがある。
そんな時は、xcodeのバージョンアップが影響している事がしばしば。
一旦以下のコマンドを実行して試してみる事をオススメする。
$ xcode-select --install
- 投稿日:2020-06-19T16:02:51+09:00
大好きなSCANDALのLINEbotを作りたいの巻1
作りたいbot
毎日決まった時間にランダムでSCANDALのMVを送るbot
※SCANDALは女性バンドです。そのための僕の頭の中の構想(railsで作成)
- まずはWEB上で動く物を作る
- それをLINEbotにする
- そこから機能を追加していく(例えば、ACIDMANとLINEで送るとACIDMANの曲をランダムに返すなど) ※ACIDMANもバンドです。
ひとまずできたこと
- まずはWEB上で動く物を作る
参考にした記事
Qiitaの記事を元にYouTube Data APIのリファレンスを参考にしました。
Qiita
https://qiita.com/sakakinn/items/46c0d4945e4646f346f6YouTube 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.rbclass 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が好きな人もぜひ。
つづく
- 投稿日:2020-06-19T15:08:09+09:00
[備忘録] [初心者] Rubyの書き方メモ(リファクタリング) 1
概要
前回の投稿で掲載していたRubyのコードがRubyらしい書き方になっていないことに気づいたので、修正も兼ねて勉強のメモを残します。
下記記事を拝見したのがきっかけで、勉強のために実際に内容を参考にさせて頂きながら前回投稿分のコードを例にして修正してみました。
[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか | Qiitaコード
修正前
Upcasing.rbdef 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.rbdef 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)を書かないようにします。Rubyhoge = true p hoge if hoge; hoge = false; end p hoge # true # falseJavaScriptvar hoge = true; console.log(hoge); if (hoge) hoge = false; console.log(hoge); // true // falseC#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]]
- Methods > [] (String) | API documentation for Ruby 2.7.1.
文字列の後ろに[]をつけて文字番号を指定できることを初めて知りました。
負のインデックスによって後ろから数えられるのは便利ですね。- Methods > [] (Array) | API documentation for Ruby 2.7.1.
配列要素の番号についても同様らしく、負のインデックスが、配列の末尾からの計算を意味することが明記されています。③ Rubyでの戻り値の表記
def Upcasing(result_lines) ## ## コード省略 ## joined_line = result_lines.join(" ") - return joined_line end
- クラス/メソッドの定義 > メソッドの評価 | Ruby 2.7.0 リファレンスマニュアル
returnが呼ばれなかった場合は、本体の最後の式の値が返されることになるので、わざわざ修正前のように1行分記載する必要がありません。④ 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}
- Hash | API documentation for Ruby 2.7.1.
記法のバリエーションや各種関連メソッドについての説明はドキュメントで説明されています。どうにかシンボルを使って表現しようとも考えたのですが、そもそもハッシュのキーに特殊文字一文字を当てる場面がそんなにあるのだろうかと疑問に思い、今回はスルーすることにしました。
この件に関して、また気づきがあれば別途投稿します。
- 投稿日:2020-06-19T12:19:56+09:00
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」にアクセスすると、アプリケーションのトップページに遷移するはずです。
以上、短く記載しました。
ここまで、全てストレートに行ったわけではなく、エラーも出力されました。この辺りは、環境や設定により様々ですので、別記事にてエラー対策を掲載したいと思います。
- 投稿日:2020-06-19T11:10:56+09:00
FinderのデフォルトテキストエディタをAtomに変更する方法
- 投稿日:2020-06-19T10:02:26+09:00
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.rbclass Place < ApplicationRecord belongs_to :user has_many :menus endRailsでは命名規則が重要なのでこの単数形と複数形の記述を間違えないように注意。
(1人の)userに対して(1つの)place、(1つの)placeに対して(複数の)menusを持ちます。belongs_to (〜に属する) has_many (たくさん持っている)・・・わかりやすいですね!
app/models/menu.rbclass Menu < ApplicationRecord belongs_to :place endmenu.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.rbclass 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.rbdef 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で登録したメニューを確認できます。
- 投稿日:2020-06-19T07:25:34+09:00
Ruby 2.7.1 で解く AtCoder ABC127 D ハッシュ
はじめに
AtCoder の過去問題の環境がバージョンアップされました。
今回のお題
AtCoder Beginner Contest D - Integer Cards
Difficulty: 891今回のテーマ、ハッシュ
問題からは優先度付きキューなのですが、制約が緩いようでソートでも解けます。
解法1 ハッシュ(2.7.1)
ruby.rbn, 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 anstally.rbh = gets.split.map(&:to_i).tally
tallyで配列からハッシュを生成しています。numberedparameter.rbh.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.rbn, 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.rbn, 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.rbclass 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

