- 投稿日:2020-01-23T23:47:38+09:00
Rspecと Factoryの使い方
Rspecとは?
Rspecとは自動テストをしてくれる言語。になります。
UIテストをいちいちせずとも、
「ページの遷移」、「モデルバリデーション」、「if分の条件分岐による処理の確認」...
などなど、人間がやるには面倒なことを自動でやってくれるのがRspecになります!準備
今回は比較的簡単な、
「コントローラーによる画面遷移確認テスト」
のコードを書いていこうと思いますまた、ログイン後の処理定義をするコードを書きますが、そのログイン処理をDeviseを使ってやるものとします
導入するGemインストール
今回使うのはRspecとFactory_botというGemを使います
内容については後ほど解説しますので、まずはインストールしましょう!!Gemfilegroup :development, :test do gem "rspec-rails" gem "factory_bot_rails" endrspecを設定・書くためのファイルを作成
$ bundle exec rails generate rspec:installdeviceログインの簡略化
controller_macros
spec/support/controller_macros.rbににログイン処理を簡略化させるためのコードを記載します
ファイルがない場合のファイルを作成してくださいspec/support/controller_macros.rbmodule ControllerMacros def login_admin(admin) @request.env["devise.mapping"] = Devise.mappings[:admin] sign_in admin end def login_user(user) controller.stub(:authenticate_user!).and_return true @request.env["devise.mapping"] = Devise.mappings[:user] sign_in user end endrails_helperで読み込み設定
先ほどのコードを読み込ませるために、spec/rails_helper.rbに以下文を追記します
spec/rails_helper.rbDir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }実装
ここからファイルに必要なコード書いていきます
テストするためのモデルを作成
spec/fatoriesこのディレクトリに作成していモデルデータを記載していきます。
今回はユーザによる画面遷移テストを作りたいので、まずユーザーファイルを作成。spec/fatories/users.rb
その後中身を書いていきます
**spec/fatories/users.rb**FactoryBot.define do factory :user do name { "test" } email { "user@email.com" } password { "password" } password_confirmation { "password" } end end今回はユーザー必要最低限な情報だけにしておきます
ここはかくじ必要なカラム等追加していただければと思います!テストコードの記載
ここから肝心なテスト内容を記載するところです
テストコードを書く場所は
spec/controllers/users_controller_spec.rb
ここになります!
コントローラー内での画面遷移テストしかできないので、他のモデルが絡むときは
随時それ対応するコントローラーでかきましょう!spec/cotrollers/users_controller_spec.rbrequire 'rails_helper' describe UsersController, type: :controller do before do @user = FactoryBot.create(:user) end context 'ログイン後' do before do login(@user) end it 'トップ画面にいく' do get :index expect(response).to have_http_status "200" end end context '未ログインの場合' do it 'トップに行くと302(エラー)が返される' do get :index expect(response).to have_http_status "302" end it 'トップに行くとuserログインページにリダイレクトされる' do get :index expect(response).to redirect_to new_user_session_path end end end・describe
→コントローラーしていし、typeでもコントローラーと指定する
→モデルの場合typeはmodelになる・before do
→テスト実行前の準備する場所
→今回で言うとここでユーザーの情報を作成して、@userに代入してuserのデータを扱えるようにしている・contxt
→実行する前提条件の定義を日本語わかりやすく、みやすくする
→実行範囲内を定義する意味もある・it
→実際にテストする内容・get: :index
→ルーティングで定義てしてるgetメソッドのindexアクションに遷移すると定義・expect(response).to have_http_status "200"
→要するに成功したら200って返ってくきてるよね??という確認
→ここがtrueかfalseかでテスト結果を判定している実行
$ rspec以上で実行完了
まとめ
以上でコントローラーテストの簡易的な説明になります
まずは簡単なところからはじめて徐々にできる範囲を伸ばしていきましょう!!
- 投稿日:2020-01-23T20:11:22+09:00
【Ruby】mapメソッドのつかいかた(+別メソッドとの組み合わせの例など)
自己整理&備忘録です。
mapメソッドとは
mapメソッドとは、「配列の要素それぞれに対して一定の処理を行って、新しい配列をつくるメソッド」とされる。
基本的な型配列.map { |変数| 実行させたい処理 }名称は異なるが
collectメソッド
もmapと同じ動きをする。つかいかた(例)
1. 数式
sample_1.rbx = [0, 100, 500] y = x.map { |x| x * 2 } p y #=> [0, 200, 1000]2.mapの要素にメソッドを与える(よく見る形)
基本の型
オブジェクト名.map(&:メソッド名)例
sports = ["BASEBALL", "SOCCER"] p sports.map(&:downcase) #=> ["baseball", "soccer"]mapとmap!の違い
map
→ 元の値に対して影響を与えない
map!
→ 元の値を書き換えるfruits = ["apple", "banana", "orange"] p fruits p fruits.map(&:upcase) p fruits p fruits.map!(&:capitalize) p fruits # 出力結果(4つ目のmap!後に元のfruitsを出力すると上書きされている) ["apple", "banana", "orange"] ["APPLE", "BANANA", "ORANGE"] ["apple", "banana", "orange"] ["Apple", "Banana", "Orange"] ["Apple", "Banana", "Orange"]eachメソッドとの違い
新しい配列を作るので、空の配列
array = []
を作らずに書くことができる。例.配列の頭文字の大文字にしたいときの
each
とmap
の違いrei.rbfruits = ["apple", "banana", "orange"] 出力結果(理想形) ["Apple", "Banana", "Orange"]
each
のときeach_ver.rbfruits = ["apple", "banana", "orange"] fruits_ini = [] fruits.each do |frt| fruits_ini << frt.capitalize end p fruits_ini #=> ["Apple", "Banana", "Orange"]
map
のときmap_ver.rbfruits = ["apple", "banana", "orange"] p fruits.map(&:capitalize) #=> ["Apple", "Banana", "Orange"]参考
Rubyのmap, map!メソッドの使い方
Ruby mapメソッドについて
【Rails入門】mapメソッドを完全攻略!配列操作の基礎を学ぼう
- 投稿日:2020-01-23T20:03:32+09:00
Railsチュートリアル 第4章
Railsコンソールの設定
Railsコンソールはirb(IRB:Interactive RuBy)を拡張して作られているため、Rubyの機能を全て使うことができる。
$ nano ~/.irbrc下記の設定を書くと、irbのプロンプトが簡潔な表示に置き換わる。
IRB.conf[:PROMPT_MODE] = :SIMPLE IRB.conf[:AUTO_INDENT_MODE] = false後続ifとunless
if:条件式が"真"のときに実行される
puts "x is not empty" if !x.empty?unless:条件式が"偽"のときに実行される
>> string = "foobar" >> puts "The string '#{string}' is nonempty." unless string.empty? The string 'foobar' is nonempty. => nilメソッド
mapメソッド
配列の要素の数だけブロック内の処理を繰り返し、結果として作成された配列を返す。
map!は元の値を書き換える。オブジェクト.map { |変数| # 実行したい処理 }>> (1..5).map { |i| i**2 } => [1, 4, 9, 16, 25]>> %w[a b c] # %w で文字列の配列を作成 => ["a", "b", "c"] >> %w[a b c].map { |char| char.upcase } => ["A", "B", "C"] >> %w[A B C].map { |char| char.downcase } => ["a", "b", "c"]mapのブロック内で宣言した引数(char)に対してメソッドを呼び出している場合は、省略記法が一般的。
>> %w[A B C].map { |char| char.downcase } => ["a", "b", "c"] >> %w[A B C].map(&:downcase) => ["a", "b", "c"]to_a
配列に変換する
>> (0..9).to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]%w
文字列の配列に変換
>> a = %w[foo bar baz quux] # %wを使って文字列の配列に変換 => ["foo", "bar", "baz", "quux"] >> a[0..2] => ["foo", "bar", "baz"]ブロック
下記では、範囲オブジェクトである(1..5)に対して、eachメソッドを呼び出している。
メソッドに渡されている{ |i| puts 2 * i }が、ブロックと呼ばれる部分。>> (1..5).each { |i| puts 2 * i }また、ブロックである事を示すには波カッコで囲むが、下記のようにdoとendで囲んで示すこともできる。
短い1行のブロックには波カッコを使い、長い1行や複数行のブロックにはdo..endを使う。>> (1..5).each do |i| ?> puts 2 * i >> endそう考えると、単体テストもブロックであることがわかる。
このtestメソッドは、文字列(説明文)とブロックを引数にとり、テストが実行されるときにブロック内の文が実行されている。test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" endハッシュ
ハッシュは本質的には配列と同じだが、インデックスとして整数値意外のものも使える点が配列とは異なる。(そのため、他の言語ではハッシュを連想配列と呼ぶこともある)
ハッシュは、キーと値のペアを波カッコで囲んで表記する。
配列と似ているが、ハッシュでは要素の並び順が保証されないため、要素の順序が重量である場合は、配列を使う必要がある。>> user = { "first_name" => "Michael", "last_name" => "Hartl" } => {"last_name"=>"Hartl", "first_name"=>"Michael"}上記では、ハッシュのキーとして文字列を使っていたが、Railsでは文字列よりもシンボルを使うのが一般的。:nameのように表す。
>> user = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> user[:name] # :name に対応する値にアクセスする => "Michael Hartl" >> user[:password] # 未定義のキーに対応する値にアクセスする => nilまた、シンボルとハッシュロケットの組み合わせを、下記のようにキーの名前の後にコロンを置く記法も同じように使える。
{ name: "Michael Hartl", email: "michael@example.com" }CSSを追加する
ハッシュを学んだので、下記が理解できるようになっている。
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>まずは、丸カッコがないが、Rubyでは丸カッコは使用しなくてもいいので、下記の2つの行は等価となる。
stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': 'reload') stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'次にmedia引数はハッシュだが、波カッコがない点が不思議。
ハッシュはメソッド呼び出しの最後の引数である場合は、波カッコを省略できるためであり、下記の2つの行は等価となる。stylesheet_link_tag 'application', { media: 'all', 'data-turbolinks-track': 'reload' } stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'Rubyでは改行と空白を区別していないため、上記のように途中に改行が含まれていても問題ない。
以上の事から、stylesheet_link_tagメソッドは、2つの引数で呼ばれており、最初の引数はである文字列は、スタイルシートへのパスを示す。
次の引数であるハッシュには2つの要素があり、最初の要素はメディアタイプを示し、次の要素はturbolinksという機能をオンにしている。
最後に上記を読み込んで生成されたHTMLソースは下記となる。<link data-turbolinks-track="true" href="/assets/application.css" media="all" rel="stylesheet" />クラス
クラスの継承
String ⇨ Object ⇨ BasicObject ⇨ nil(スーパークラスを持たないという事)
Array、Hashなどのクラスも上記と同様である。これが"Rubyではあらゆる物がオブジェクトである"という事。>> s = String.new("foobar") => "foobar" >> s.class => String >> s.class.superclass => Object >> s.class.superclass.superclass => BasicObject >> s.class.sクラス継承の例
>> class Word < String # WordクラスはStringクラスを継承する >> # 文字列が回文であればtrueを返す >> def palindrome? >> self == self.reverse # selfは文字列自身を表します >> end >> end => :palindrome?上記の様に、WordクラスはStringクラスを継承しているため、palindrome?メソッドだけでなく、Stringクラスが扱える全てのメソッドがWordクラスでも扱える様になる。
>> s = Word.new("level") # 新しいWordを作成し、"level" で初期化する => "level" >> s.palindrome? # Wordが回文かどうかを調べるメソッド => true >> s.length # WordはStringで扱える全てのメソッドを継承している => 5selfキーワード
selfとは、オブジェクトそのものを指している。
attr_accesssorメソッド
クラスにインスタンス変数を読み書きするためのアクセサメソッドを定義するメソッド。
アクセサメソッドは、外部インスタンスのインスタンス変数を参照したり変更するために定義する。initialize
User.newを実行すると自動的に呼び出されるメソッド。
- 投稿日:2020-01-23T19:28:00+09:00
Alpineベースのimageにruby2.2.3を入れる
本当はalpine-rubyをベースにするべきなんだろうけど諸事情でJava系のベースにする必要があったので、rbenvを自力で入れて構築することにしました。
出来上がったDockerfileはこちら。
FROM openjdk:8-jdk-alpine RUN apk update && \ apk upgrade && \ apk add --update --no-cache \ bash \ vim \ curl \ tzdata RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ apk del tzdata RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.8/main" >> /etc/apk/repositories RUN apk update && \ apk upgrade && \ apk add --update --no-cache --virtual=.build-dependencies \ build-base \ git \ gcc \ readline-dev \ openssl-dev=1.0.2u-r0 \ zlib-dev \ libffi-dev ENV PATH /usr/local/rbenv/shims:/usr/local/rbenv/bin:$PATH ENV RBENV_ROOT /usr/local/rbenv ENV CONFIGURE_OPTS "--disable-install-doc" RUN git clone https://github.com/sstephenson/rbenv.git ${RBENV_ROOT} && \ git clone https://github.com/sstephenson/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build && \ ${RBENV_ROOT}/plugins/ruby-build/install.sh RUN echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> /etc/profile.d/rbenv.sh && \ echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh RUN rbenv install 2.2.3 && \ rbenv global 2.2.3 COPY Gemfile . COPY Gemfile.lock . RUN gem install -N bundler -v 1.16.2 RUN bundle install -j4 && \ rm -rf /usr/local/bundle/cache/*.gem RUN apk del .build-dependencies大きな障害はは以下のようにopensslの1.0を取得することでした。
v3.8から1.0系のopensslを取得する
素直にapk add opensslでライブラリを入れるとrbenv install時に以下のようなエラーが発生する。
BUILD FAILED (Alpine Linux 3.9.4 using ruby-build 20200115-8-g73b926b) Inspect or clean up the working tree at /tmp/ruby-build.20200123165940.26.gjbJCo Results logged to /tmp/ruby-build.20200123165940.26.log Last 10 log lines: power_assert-0.2.2.gem minitest-5.4.3.gem installing rdoc: /usr/local/rbenv/versions/2.2.3/share/ri/2.2.0/system installing capi-docs: /usr/local/rbenv/versions/2.2.3/share/doc/ruby The Ruby openssl extension was not compiled. ERROR: Ruby install aborted due to missing extensions Configure options used: --prefix=/usr/local/rbenv/versions/2.2.3 LDFLAGS=-L/usr/local/rbenv/versions/2.2.3/lib CPPFLAGS=-I/usr/local/rbenv/versions/2.2.3/includeエラーの原因としては、ruby2.4以下の場合はopenssl1.1系に対応していないため、openssl1.0を入れる必要があるからでした。
rbenv/ruby-buildThe openssl extension of Ruby version before 2.4 is not compatible with OpenSSL 1.1.x.
ubuntuベースのimageで構築するならこちらの記事で言及されているように有志が開発したパッチを当てれば動きますが、alpineの場合は自力で1.0系を入れる必要があります。
現在openjdk:8-jdk-alpineではデフォルトでv3.9のリポジトリを参照しているが、v3.9ではopensslは1.1系の提供になっています。
こちらで調べると1.0系の取得には1つ前のv3.8のリポジトリから取得が必要のようです。
https://pkgs.alpinelinux.org/packages?name=openssl&branch=v3.8&repo=mainそこでapkから取得する前に参照先にv3.8のリポジトリを追加して上げる必要があります。
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.8/main" >> /etc/apk/repositories追加後に
openssl-dev=1.0.2u-r0
とバージョンを指定することで1.0系のopensslを取得することができます。また当初はgem install時に
The Ruby openssl extension was not compiled. Missing the OpenSSL lib?
エラーが発生していたが、修正前のDockerfikeでlibssl1.0
を入れていたことが原因でした。
おそらくssl系のライブラリ同士でバッティングしていたっぽい?rbenvの前はruby-installを使用して軽量化を図っていましたが、上と同じOpenSSLのエラーがどうしても解消できなかったので諦めることに…
ruby-installで上手く行けば多分もう少し軽くできそう。RUN wget -O - https://github.com/postmodern/ruby-install/archive/v0.7.0.tar.gz | tar xzvf - && \ ( cd ruby-install-0.7.0 && \ make install ) && \ rm -rf ruby-install-* RUN ruby-install --system --cleanup ruby 2.2.3その他細かいポイントなど
docker軽量化系の記事では散々言及されているようなことですが、軽くまとめると
- ビルドに必要のないパッケージは残したくないので.build-dependenciesでまとめて最後の行で一括で削除しています。
-ENV CONFIGURE_OPTS "--disable-install-doc"
を指定することで不要なドキュメントをインストールしないようにしています
- bundle install時にrm -rf /usr/local/bundle/cache/*.gem
でgemのキャッシュを消すようにしています今どき2.2.3を使うことはあまりないと思いますが、備忘録として残しておこうと思います。
- 投稿日:2020-01-23T19:11:19+09:00
【rails】ユーザー 登録時にnameカラムに自動的に@を付ける方法
はじめに
初学者がポートフォリオ作成でハマったことをメモします。
TiwtterのアカウントIDのように特定のカラムの最初に@を付ける方法です。ホートフォリオ作成時にユーザーの名前やアカウントIDの最初に@を付けたいという方は多いと思います。
初歩的な内容すぎて調べてもそのような記事がすぐ見つからなかったので残しておきます。結論
before_save
をmodelに設定する。コードと説明
formから送られてきた値を保存する前に加工する。
before_saveは、paramsをDBに保存する直前に指定したプログラム(今回の例では、:change_account_name)を実施するコールバック関数です。
before_saveを設定すると、createとupdateのどちらも場合にも、適用されます。models/user.rbbefore_save :change_account_name def change_account_name self.account_name = "@" + account_name endviews/users/new#slim,bootstrap使用 = form_with model: @user, local: true do |f| (中略) = f.label :account_name, 'アカウントID' .input-group .input-group-prepend .input-group-text @ = f.text_field :account_name, class: 'form-control' , placeholder: "9文字まで"終わりに
誰かのお役に立てれば幸いです。
間違えている部分があればコメントお願い致します。参考にした記事
https://qiita.com/KeisukeYoshida0220/items/e1ce152ac8d89845aab3
- 投稿日:2020-01-23T17:34:48+09:00
【Ruby】ヒアドキュメントの初歩的なつかいかた
- 投稿日:2020-01-23T16:31:14+09:00
#Ruby / nested Array elements / map and delete / Broken modified original array / So use dup ( deep copy )
# GOOD # dup element in map arr = [[:A, :B], [:C, :D]]; changed_arr = arr.map { |a| x = a.dup; x.delete_at(-1); x }; p changed_arr; p arr # [[:A], [:C]] # [[:A, :B], [:C, :D]] # BAD # map and delete arr = [[:A, :B], [:C, :D]]; changed_arr = arr.map { |a| a.delete_at(-1); a }; p changed_arr; p arr # [[:A], [:C]] # [[:A], [:C]] # BAD # dup array and map and delete arr = [[:A, :B], [:C, :D]]; dupped_arr = arr.dup; changed_arr = dupped_arr.map { |a| a.delete_at(-1); a }; p changed_arr; p arr # [[:A], [:C]] # [[:A], [:C]]Original by Github issue
- 投稿日:2020-01-23T15:03:19+09:00
#Ruby で配列の添字・順序を文字列から探す ( find_index )
- 投稿日:2020-01-23T14:44:37+09:00
Railsチュートリアル 第3章
この章では、テスト駆動開発について学習。
テスト
Railsのテストには、コントローラーテスト、モデルテスト、統合テストの3種類ある。
ここでは、コントローラーテストについてメモ。テストの例を2つほど
test "should get home" do get static_pages_home_url ⇨GETリクエストをhomeアクションに対して発行 assert_response :success ⇨リクエストに対するレスポンスは"成功"になるはず endtest "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Home | Ruby on Rails Tutorial Sample App" ⇨titleタグ内に「Home | Ruby on Rails Tutorial Sample App」と言う文字列があるはず endsetupメソッド
書くテストが実行される直前で実行されるメソッド。
provideメソッド
provideメソッドでパラメータを引き渡す
<% provide(:title, "Home") %>yieldメソッドで受け取る
<title><%= yield(:title) %></title>テストの便利な設定
テスト用の設定として、minitest reportersとGuardについてメモ。
minitest reporters
テストの結果をプログレスバーでパーセント表示したり、REDやGREENで表示してくれる設定。
minitest-reporters gemを利用。Gemfile.rbsource 'https://rubygems.org' . . group :test do gem 'rails-controller-testing', '1.0.2' gem 'minitest', '5.10.3' gem 'minitest-reporters', '1.1.14' ⇦これを追加 gem 'guard', '2.13.0' gem 'guard-minitest', '2.4.4' end . .test/test_helper.rbENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' require "minitest/reporters" ⇦これを追加 Minitest::Reporters.use! ⇦これを追加 class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests # in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... endGuardによるテストの自動化
rails testコマンドを手動で打ち込まなくても、static_pages_test.rbファイルなどを変更すると自動的にテストを実行してくれるツール。
Gemfile.rbsource 'https://rubygems.org' . . group :test do gem 'rails-controller-testing', '1.0.2' gem 'minitest', '5.10.3' gem 'minitest-reporters', '1.1.14' gem 'guard', '2.13.0' ⇦これを追加 gem 'guard-minitest', '2.4.4' ⇦これを追加 end . .初期化
$ bundle exec guard initCloud9を使っている場合は、tmuxをインストールする必要がある。
$ sudo yum install -y tmuxGuardfile編集
Guardfile.rb# Guardのマッチング規則を定義 guard :minitest, spring: "bin/rails test", all_on_start: false do watch(%r{^test/(.*)/?(.*)_test\.rb$}) watch('test/test_helper.rb') { 'test' } watch('config/routes.rb') { integration_tests } watch(%r{^app/models/(.*?)\.rb$}) do |matches| "test/models/#{matches[1]}_test.rb" end watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches| resource_tests(matches[1]) end watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches| ["test/controllers/#{matches[1]}_controller_test.rb"] + integration_tests(matches[1]) end watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches| integration_tests(matches[1]) end watch('app/views/layouts/application.html.erb') do 'test/integration/site_layout_test.rb' end watch('app/helpers/sessions_helper.rb') do integration_tests << 'test/helpers/sessions_helper_test.rb' end watch('app/controllers/sessions_controller.rb') do ['test/controllers/sessions_controller_test.rb', 'test/integration/users_login_test.rb'] end watch('app/controllers/account_activations_controller.rb') do 'test/integration/users_signup_test.rb' end watch(%r{app/views/users/*}) do resource_tests('users') + ['test/integration/microposts_interface_test.rb'] end end # 与えられたリソースに対応する統合テストを返す def integration_tests(resource = :all) if resource == :all Dir["test/integration/*"] else Dir["test/integration/#{resource}_*.rb"] end end # 与えられたリソースに対応するコントローラのテストを返す def controller_test(resource) "test/controllers/#{resource}_controller_test.rb" end # 与えられたリソースに対応するすべてのテストを返す def resource_tests(resource) integration_tests(resource) << controller_test(resource) endGuard使用時のSpringとGitの競合を防ぐには、.gitignoreファイルにspring/ディレクトリを追加する。
そうすることで、指定したファイルはGitリポジトリに追加されなくなる。.gitignore# See https://help.github.com/articles/ignoring-files for more about # ignoring files. # # If you find yourself ignoring temporary files generated by your # text editor or operating system, you probably want to add # a global ignore instead: # git config --global core.excludesfile '~/.gitignore_global' # Ignore bundler config. /.bundle # Ignore the default SQLite database. /db/*.sqlite3 /db/*.sqlite3-journal # Ignore all logfiles and tempfiles. /log/* /tmp/* !/log/.keep !/tmp/.keep # Ignore Byebug command history file. .byebug_history # Ignore Spring files. /spring/*.pid ⇦これを追加設定が完了したので実行
$ bundle exec guard
- 投稿日:2020-01-23T14:03:03+09:00
RubyでLeetCodeを解いてみた Palindrome Number
https://leetcode.com/problems/palindrome-number/
Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.
# @param {Integer} x # @return {Boolean} def is_palindrome(x) return false if x.negative? if x.positive? arr = x.to_s.chars size = arr.size arr.each_with_index do |ele, idx| return false if ele != arr[size - idx - 1] end return true end return true if x.zero? endCoud you solve it without converting the integer to a string?
文字列に変換しないパターンは思いつかなかった?
- 投稿日:2020-01-23T11:10:53+09:00
rakeタスクに引数を渡したいとき
rakeタスクで引数を渡したい!
意外とまとまった記事がなかったので備忘。タスク名とともに引数を書く
task :task_name, ['filter'] => :environment do |_task, args| p args p args[:filter] ~
filter
の部分は任意の文字でOKタスク実行方法
command:
rake "task_name[arg]"
arg
部分に渡したい引数を書く。この場合だと "arg" が渡される。
タスク全体を "" で囲まないと、引数までタスクとして認識されない。実行結果
=> #<Rake::TaskArguments filter: arg> "arg"
- 投稿日:2020-01-23T09:18:32+09:00
【Rails】kaminari&ransackでページネーションと検索機能を実装
【ページネーション】
1ページあたり20件に設定。
スタイルはBootstrap4で実装します。【検索機能】
投稿一覧から検索とブックマーク済み投稿一覧から検索の2パターン実装していきます。
検索条件はタイトルか本文の部分一致とします。【事前準備】
・ブックマーク機能を実装しておいてください。
参考資料:【Rails】ブックマーク(お気に入り)機能
・bootstrap4を使用できるように設定しておいてください。
参考資料:BootstrapをRailsに導入してみよう!徹底解説!環境
Rails 5.2.3
mysql 5.7.28
gem kaminari
gem ransack
実装
それでは実装していきます。
gemの追加
gem kaminari
gem ransack
Gemfileに追加し、
bundle install
Gemfilegem 'kaminari' gem 'ransack'ターミナル$ bundle installページネーション実装
まずはページネーションから実装していきます。
ターミナルで
kaminari
の設定ファイルを自動生成するコマンドを入力します。ターミナル$ rails g kaminari:configこれで
kaminari
の動作を変えるために必要な設定ファイルを生成できます。次にページネーション用のビューファイルをを自動生成するコマンドを入力します。
ターミナル$ rails g kaminari:views bootstrap4これでbootstrap4のページネーションのデザインに合わせたビューファイルが自動で生成されます。
次に1ページあたりのデータ取得数を書き換えます。
デフォルトでは25件のデータを取得する設定になっています。config/initializers/kaminari_config.rb# frozen_string_literal: true Kaminari.configure do |config| config.default_per_page = 20 # 25から20に書き換え # config.max_per_page = nil # config.window = 4 # config.outer_window = 0 # config.left = 0 # config.right = 0 # config.page_method_name = :page # config.param_name = :page # config.params_on_first_page = false end次はコントローラーにpageメソッドを追加していきます。
board_controller.rbdef index @boards = Board.includes(:user).page(params[:page]) end def bookmarks @boards = current_user.bookmark_boards.includes(:user).page(params[:page]) end
kaminari
をインストールしたことでモデルクラスに対してpageメソッド
が使用できるようになります。
先ほど設定した1ページあたりのデータ取得件数を引数のparams[:page]
に格納し、ビューで表示するようにします。この時点で1ページ目には20件のデータが表示されているはずです。
2ページ目以降も見れるようにリンクを貼ります。
リンクを貼りたい箇所に<%= paginate @boards %>
を記述すればOKです。
サーバーを再起動して、このようなリンクが表示されていれば実装完了です。日本語化
実装は完了ですが英語の部分を日本語化しておきます。
デフォルトのロケール(言語)を日本語にします。
config/application.rbmodule アプリ名 class Application < Rails::Application # 追記↓ config.i18n.default_locale = :ja次に日本語訳を設定するファイルを作成・記述していきます。
config/locales/ja.yml
を作成し任意の日本語を記述していきます。config/locales/ja.ymlja: views: pagination: first: 最初 last: 最後 previous: 前 next: 次 truncate: ...これで設定が完了したのでサーバーを再起動したら反映されているはずです。
検索機能実装
controllerを編集
boards_controller.rbdef index @q = Board.ransack(params[:q]) # 検索オブジェクト作成 @boards = @q.result.includes(:user).page(params[:page]) # 検索結果(検索しなければ全件取得) end def bookmarks @q = current_user.bookmark_boards.ransack(params[:q]) # 検索オブジェクト作成 @boards = @q.result.includes(:user).page(params[:page]) # 検索結果(検索しなければ全件取得 endviewを編集(検索フォーム)
boards/index.html.erb<!-- 検索フォーム --> <%= render 'search_form', url: boards_path, q: @q %>boards/bookmarks.html.erb<!-- 検索フォーム --> <%= render 'search_form', url: bookmarks_boards_path, q: @q %>_search_form.html.erb<%= search_form_for q, url: url do |f| %> <div class="input-group mb-3"> <%= f.search_field :title_or_body_cont, class: "form-control", placeholder: '検索ワード' %> <div class="input-group-append"> <%= f.submit "検索", class: "btn btn-primary" %> </div> </div> <% end %>
<%= search_form_for q, url: url do |f| %>
のurlを一覧とブックマーク一覧のurlで指定することでその範囲内から検索をすることができます。
<%= f.search_field :title_or_body_cont,...
でtitleカラムとbodyカラムのどちらからでも検索が部分的に一致すれば表示されます。
条件はこちらのサイトを参考にしました。
Ransackで簡単に検索フォームを作る73のレシピviewを編集(検索結果一覧)
index.html.erb,bookmarks.html.erb共通<!-- 掲示板一覧 --> <% if @boards.any? %> <div class="row d-flex"> <%= render @boards %> </div> <% else %> <h1><%= '検索結果がありません。' %></h1> <% end %> <%= paginate @boards %>これでインスタンスにデータが存在すれば一覧表示され、なければ検索結果がありませんと表示されます。
まとめ
わりとすんなり実装できたかなと思います。
詰まったとことしては検索範囲を全boardとbookmark_boardで範囲分けする部分でしたが、urlを検索範囲に指定することで解決しました。
- 投稿日:2020-01-23T09:02:23+09:00
enumを導入すると起きるエラー【rails】
概要
数字を文字列に変換してくれる最強助っ人「enum」ちゃんを導入するとエラー発生。
エラー文
'x'ArgumentError in xxx
'x' is not a valid xxx解決方法
Shift_user.model(enumを書いているモデル)での定義ミス。
詳細
Before↓
model.rbclass ShiftUser < ApplicationRecord enum work_type:{ "午前": 1, "午後": 2, "一日": 3, } endAfter↓
model.rbclass ShiftUser < ApplicationRecord enum work_type: { am: 1, pm: 2, all_day: 3 } # 英語から日本語 WORK_TYPE = { am: '午前', pm: '午後', all_day: '1日' }そもそもenumで日本語でも指定はできるが、
よく使われるのが「アルファベット or _」を使って命名するらしい。
- 投稿日:2020-01-23T08:13:35+09:00
【Rails】 DataTables のテーブルに関連付けされたモデルのデータを表示する方法
はじめに
DataTableへデータを渡すときに json 形式に変換する必要があります。
関連付けされたモデルのデータを簡単に json 形式に変換することができます。関連リンク
関連リンクを下記に載せておくので、必要であれば参考にしてください。。
- 【Rails】 DataTables 実装方法
- 【Rails】 DataTables 動的にカラムを変更する方法
- 【Rails】 DataTables 検索結果の保持方法
関連付けされたモデルのデータを表示する方法
as_json の include をすることで user に関連付けされた post のデータを一緒に json のデータとして作成してくれます。
app/datatables/users_datatable.rbclass UsersDatatable # *** 省略 *** def as_json(options = {}) { recordsTotal: User.count, # 取得件数 recordsFiltered: users.total_count, # フィルター前の全件数 # user モデルに関連付けされた post モデルを include して json ファイルを作成する。 data: users.as_json(include: :post), # 表データ } end # *** 省略 *** endまとめ
こちらは突き詰めると、 DataTable 特有の使い方ではなく、 json ファイルの作り方の記事になってしまっています。
使い方が全くわからないという方には少しは参考になるかなーと思い投稿させていただきました。
- 投稿日:2020-01-23T01:16:34+09:00
初学者によるプログラミングMemo #18 フィボナッチ数列(メモ化)
はじめに
今回はフィボナッチ数列のお話です
なお、本記述はMacにおいて、Railsでの開発を前提としています
また、まだまだひよっこですので、不備等ございましたらご指摘いただけると幸いです
*追記
コメント欄に簡潔なコードがありますので、そちらもご覧ください
元の記述は自分が考えた軌跡として残しておきます目次
- フィボナッチ数列とは
- プログラムで解いてみる
フィボナッチ数列とは
初項 = 1、第2項 = 1、第3項以降は、前項と前々項の和となる数列です
第3項は初項と第2項の和なので「1+1」で"2"となります
第4項は第2項と第3項の和なので"3"となります
また、フィボナッチ数列は黄金比とも関係してるので、知りたい方は調べてみてください
数列としては、「1,1,2,3,5,8,13,21,34,55,・・・」と続きますこの数列の第n項目は何になるかを求めたいと思います
プログラムで解いてみる
では、プログラムで解いてみましょう
まずは、フィボナッチ数列がどういうものだったかを思い出しましょうfib(n) = fib(n-2) + fib(n-1)第n項は前(n-1)項と前々(n-2)項の和でしたよね
しかし、初項と第2項は決まっています
付け加えましょうfib(n) = fib(n-2) + fib(n-1) fib(0) = 1 fib(1) = 1できました
このままではプログラムとしては成り立っていませんので、組み立てましょうdef fib(n) if n == 0 || n == 1 return 1 else fib(n-2) + fib(n-1) end endできました
しかし、このプログラムには欠点があります
fib(4)で解説しましょうfib(4) = fib(3) + fib(2)ですね
でも、fib(3)とfib(2)も求めないといけないですよね
そうするとfib(4) = fib(3) + fib(2) fib(3) = fib(2) + fib(1) fib(2) = fib(1) + fib(0)こうなりますが、fib(3)の中にもfib(2)が入っていますね
そうするとこうなりますfib(4) = fib(3) + fib(2) fib(3) = fib(2) + fib(1) #fib(4)の中のfib(3)を求める式 fib(2) = fib(1) + fib(0) #fib(3)の中のfib(2)を求める式 fib(2) = fib(1) + fib(0) #fib(4)の中のfib(2)を求める式ここで違和感というか、無駄が発生していることにお気づきでしょうか
fib(2)は2回、fib(1)とfib(0)は3回出てきています
nが小さい時はあまり問題がありませんが、n=30くらいになると、答えが返ってくるまでに時間がかかります
n=35で2秒ほどかかります
n=100では計算が終わらないようですので、実行はしないようにしましょうメモ化を使う
問題が発見されたので、変更しないといけませんね
使えないこともないコードならまだしも、n=100程度でギブアップするなんて使えないコードです
そこで、メモ化というものを使います
配列に入れてしまいましょう
メモ化の特徴としては、記憶領域と引き換えに、時間のコストを削減するというものがあります
いわゆるトレードオフをする必要があるということですF = [] def fib(n) if n == 0 || n == 1 return 1 elsif F[n] != nil #ここだけのプログラムであれば不要(関与しない) return F[n] else F[n] = fib(n - 2) + fib(n - 1) end endできました
変更点は、配列をつくって、それに入れている部分です
しかしこれでは数学的には間違っているので、対話型のプログラムにしつつ正しくしましょうF = [] def fib(n) if n == 0 || n == 1 return 1 elsif F[n] != nil return F[n] else F[n] = fib(n - 2) + fib(n - 1) end end p "フィボナッチ数列の何項目が知りたいん?うちが教えたるで" num = gets.to_i if num >= 1 p fib(num-1) else p "ちゃんと入力しやん人はいややぁ" endできました
数学的な一般項はなかなか複雑ですが、プログラム上での一般項(?)はわかりやすくていいですね