- 投稿日: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-23T23:01:06+09:00
Rails 真偽値を返すメソッド 一覧
Railsで実行できる真偽判定メソッドをまとめました。
any?
文字列や配列が空でない場合にtrueを返す。
>> a = ["a"] => ["a"] >> a.any? => trueempty?
文字列や配列が空の場合にtrueを返す。
nilに対してempty?メソッドを呼び出すと、NoMethodErrorが発生する。>> a = "" => "" >> a.empty? => true >> b = nil => nil >> b.empty? NoMethodError (undefined method `empty?' for nil:NilClass)nil?
nilの場合のみtrueを返す。それ以外はfalseを返す。
>> a = nil => nil >> a.nil? => trueblank?
empty?とnil?が合わさったメソッド。
>> a = "" => "" >> b = nil => nil >> a.blank? => true >> b.blank? => truepresent?
!blank?を実行するメソッド。
>> a = 1 => 1 >> a.present? => true
- 投稿日:2020-01-23T22:03:13+09:00
Active Storageにも、1対1対応のモデルを作ったほうがいいかも
Rails 5.2から、Active Storageという、ファイルアップロードの機能が標準装備されましたが、そのまま使おうとしたところ、微妙に気になる点がありました。
Active Storageの便利な点
今までPaperclipなどのサードパーティーのGemを使っていたのですが、以下のような点を自前で実装する必要がありました。
- S3でprivate保管していると、画像表示用に生成したpresigned URLが期限切れするという問題があるので、いったんRailsを経由させてS3のURLにリダイレクトさせる必要がある
- オンデマンドに適切なサイズのサムネイルを生成するのが難しい
Active Storageであれば、こういった引っかかりやすい箇所も標準で備えていて、しかも「複数オリジンの並行運用」なんてことまでこなせてしまいます。
使い方について
Active Storageは専用のデータベーステーブルを持って、ポリモーフィック関連で別なモデルと結びつきますので、画像を入れたいモデル側でのマイグレーションは不要です。
has_one_attached :item
やhas_many_attached :items
のように宣言するだけで画像を使えるようになります。そのまま使おうとして気になったこと
もちろんそのままでも基本的なファイル保存などは問題ないのですが、使いづらい点がいくつかありました。
- モデルが
ActiveStorage::Attachment
で固定なので、
- 自分でメソッドを生やそうにもオープンクラスになってしまい、抵抗がある
- 画像ファイルに付随するタイトルなどのデータを保存できない
has_many_attached
の場合、accepts_nested_attributes_for
でファイルの追加はできるけど削除が利かない画像用モデルを立てる
ということで、画像と1対1で結びつくモデルを立てて、そこにタイトルを入れたり、画像処理用のメソッドを追加したりすることでより便利に使えて、そして
accepts_nested_attributes_for
からの_destroy
もできるようになるので、この方法が良さそうだと感じました。
- 投稿日:2020-01-23T20:51:04+09:00
【Rails】外部キー追加におけるreference型の使用、未使用の違い。外部キー制約によるエラーをコンソールで確認してみた。
概要
アソシエーション設定時にテーブルへ外部キーを追加していく中で、
reference型を使用して外部キーを追加した場合と
integer型で外部キーを追加した場合について違いを確認していきます。外部キー追加時のreference型について
例えば、UserモデルとBlogモデルで
Blogモデルにuser_idを外部キーとして設定する場合、
モデル作成と同時に設定するなら、以下のように記述して外部キーを追加することができます。reference型を使用する場合
$ rails g model Blog title:string content:text user:references
マイグレーションファイルはこのようになります。class CreateBlogs < ActiveRecord::Migration[5.2] def change create_table :blogs do |t| t.string :title t.text :content t.references :user, foreign_key: true t.timestamps end end end
マイグレーションすると、schema.rbenable_extension "plpgsql" create_table "blogs", force: :cascade do |t| t.string "title" t.text "content" t.bigint "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_blogs_on_user_id" end create_table "users", force: :cascade do |t| t.string "name" t.integer "age" t.datetime "created_at", null: false t.datetime "updated_at", null: false end add_foreign_key "blogs", "users" end
reference型を使わず、カラム名をuser_idにしてinteger型で記述する場合
$ rails g model Blog title:string content:text user_id:integerclass CreateBlogs < ActiveRecord::Migration[5.2] def change create_table :blogs do |t| t.string :title t.text :content t.integer :user_id t.timestamps end end end
これをマイグレーションすると、
schema.rbenable_extension "plpgsql" create_table "blogs", force: :cascade do |t| t.string "title" t.text "content" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.string "name" t.integer "age" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end
どちらも外部キーとしてuser_idが追加されました。
しかし、reference型にはuser_id以外にも追加されているコードがあります。
これがこの2つの方法の違いで、reference型を使うと外部キー制約、インデックスが自動で追加されます。
reference型を使わない場合はどちらも付与されません。外部キー制約とは
外部キー制約が付与された場合、以下2点の成約が付きます。
1,存在しない値の外部キーは登録できない(参照整合性)
2,親テーブル(user)の外部キーが子テーブル(blog)に登録されていると親テーブルは削除できない。1を簡単に言い直すと
主キーとして存在しないuser_idをblogsテーブルには登録できないようになるということです。コンソール上で試してみる
実際にコンソール上で試してみましょう。
user_id(1)のUserを作成します。
その後、Blogを作成しますが、外部キーにuser_id(1)とuser_id(3)(存在していないuser_id)のどちらもBlogの作成に成功しています。
外部キー制約が付与されていれば、存在していないuser_idであるuser_id(3)が含まれたBlogはエラーが発生して作成することはできません。irb(main):001:0> User.create(name: "test1", age: 10) (0.1ms) BEGIN User Create (1.2ms) INSERT INTO "users" ("name", "age", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "test1"], ["age", 10], ["created_at", "2020-01-23 03:47:53.740490"], ["updated_at", "2020-01-23 03:47:53.740490"]] (23.2ms) COMMIT => #<User id: 1, name: "test1", age: 10, created_at: "2020-01-23 03:47:53", updated_at: "2020-01-23 03:47:53">irb(main):003:0> Blog.create(title: "test1", content: "test1", user_id: 1) (0.1ms) BEGIN Blog Create (1.2ms) INSERT INTO "blogs" ("title", "content", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "test1"], ["content", "test1"], ["user_id", 1], ["created_at", "2020-01-23 03:48:48.383505"], ["updated_at", "2020-01-23 03:48:48.383505"]] (4.9ms) COMMIT => #<Blog id: 1, title: "test1", content: "test1", user_id: 1, created_at: "2020-01-23 03:48:48", updated_at: "2020-01-23 03:48:48"> irb(main):004:0> Blog.create(title: "test1", content: "test1", user_id: 3) (0.2ms) BEGIN Blog Create (0.5ms) INSERT INTO "blogs" ("title", "content", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "test1"], ["content", "test1"], ["user_id", 3], ["created_at", "2020-01-23 03:48:56.834930"], ["updated_at", "2020-01-23 03:48:56.834930"]] (1.7ms) COMMIT => #<Blog id: 2, title: "test1", content: "test1", user_id: 3, created_at: "2020-01-23 03:48:56", updated_at: "2020-01-23 03:48:56">
次に、2の制約についてですが、
blog_id(1)のBlogにはuser_id(1)が外部キーとして登録されているので、user_id(1)のユーザーを削除しようとしてもエラーが発生するということです。1,2の制約のどちらもエラーを発生させるために、外部キー制約をマイグレーション実行後に追加してみます。
後から追加する場合は
add_foreign_key :blogs, :users
( add_foreign_key :対象のテーブル, :指定先のテーブル)
をロールバックしたマイグレーションファイルに追記します。def change create_table :blogs do |t| t.string :title t.text :content t.integer :user_id t.timestamps end add_foreign_key :blogs, :users end end
rails db:rollback
して追記した後に再度rails db:migrate
を実行します。そして、先程と同じように存在しないuser_id(3)を外部キーとして、
Blogを作成しようとするもエラーが発生します。irb(main):001:0> Blog.create(title: "test2", content: "test2", user_id: 3) (0.1ms) BEGIN Blog Create (5.7ms) INSERT INTO "blogs" ("title", "content", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "test2"], ["content", "test2"], ["user_id", 3], ["created_at", "2020-01-23 04:03:15.314345"], ["updated_at", "2020-01-23 04:03:15.314345"]] (0.2ms) ROLLBACK Traceback (most recent call last): 1: from (irb):1 ActiveRecord::InvalidForeignKey (PG::ForeignKeyViolation: ERROR: insert or update on table "blogs" violates foreign key constraint "fk_rails_40ebb3948d") DETAIL: Key (user_id)=(3) is not present in table "users". : INSERT INTO "blogs" ("title", "content", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"続いて2の制約についてエラーを発生させるために試してみます。
user_id(2)に紐付いたBlogを作成します。
irb(main):005:0> Blog.create(title: "test1", content: "test1", user_id: 2) (0.2ms) BEGIN Blog Create (0.7ms) INSERT INTO "blogs" ("title", "content", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "test1"], ["content", "test1"], ["user_id", 2], ["created_at", "2020-01-23 04:08:42.845532"], ["updated_at", "2020-01-23 04:08:42.845532"]] (4.0ms) COMMIT => #<Blog id: 2, title: "test1", content: "test1", user_id: 2, created_at: "2020-01-23 04:08:42", updated_at: "2020-01-23 04:08:42">
親レコードのuser_id(2)を削除してみると、エラーが発生します。
irb(main):008:0> User.find(2).destroy User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]] (0.2ms) BEGIN User Destroy (2.5ms) DELETE FROM "users" WHERE "users"."id" = $1 [["id", 2]] (0.1ms) ROLLBACK Traceback (most recent call last): 1: from (irb):8 ActiveRecord::InvalidForeignKey (PG::ForeignKeyViolation: ERROR: update or delete on table "users" violates foreign key constraint "fk_rails_40ebb3948d" on table "blogs") DETAIL: Key (id)=(2) is still referenced from table "blogs". : DELETE FROM "users" WHERE "users"."id" = $1この通り、外部キー制約がついた状態では子レコードを削除してからでないと親レコードを削除できなくなっています。
親レコードを削除する時にいちいち子レコードを全て削除するのは手間がかかりますが、
Userモデルにhas_many :blogs, dependent: :destroy
を記述すれば、解決されます。
この記述でUserを削除した際に紐付いている子レコードのblogも一緒に削除してくれますね。user.rbclass User < ApplicationRecord has_many :blogs, dependent: :destroy end
irb(main):002:0> User.find(2).destroy User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]] (0.1ms) BEGIN Blog Load (0.4ms) SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = $1 [["user_id", 2]] Blog Destroy (0.4ms) DELETE FROM "blogs" WHERE "blogs"."id" = $1 [["id", 2]] User Destroy (0.5ms) DELETE FROM "users" WHERE "users"."id" = $1 [["id", 2]] (0.5ms) COMMIT => #<User id: 2, name: "test2", age: 20, created_at: "2020-01-23 03:48:02", updated_at: "2020-01-23 03:48:02">
親レコードと子レコードを一緒に削除できました!
インデックスについてはエラーを試す場面がないので、以下参照。
https://qiita.com/seiya1121/items/fb074d727c6f40a55f22
- 投稿日: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: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:55:29+09:00
therubyracer のエラー
bundle install
次のエラーがでました?
エラー内容Building native extensions. This could take a while... ERROR: Error installing therubyracer: ERROR: Failed to build gem native extension. current directory: /Users/koichi/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/therubyracer-0.12.3/ext/v8 /Users/koichi/.rbenv/versions/2.3.4/bin/ruby -r ./siteconf20200120-28144-771md0.rb extconf.rb checking for main() in -lpthread... yes checking for main() in -lobjc... yes checking for v8.h... no *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/Users/koichi/.rbenv/versions/2.3.4/bin/$(RUBY_BASE_NAME) --with-pthreadlib --without-pthreadlib --with-objclib --without-objclib --enable-debug --disable-debug --with-v8-dir --without-v8-dir --with-v8-include --without-v8-include=${v8-dir}/include --with-v8-lib --without-v8-lib=${v8-dir}/lib /Users/koichi/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/libv8-3.16.14.19/ext/libv8/location.rb:50:in `configure': By using --with-system-v8, you have chosen to use the version (Libv8::Location::System::NotFoundError) of V8 found on your system and *not* the one that is bundled with the libv8 rubygem. However, your system version of v8 could not be located. Please make sure your system version of v8 that is compatible with 3.16.14.19 installed. You may need to use the --with-v8-dir option if it is installed in a non-standard location from /Users/koichi/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/libv8-3.16.14.19/lib/libv8.rb:7:in `configure_makefile' from extconf.rb:32:in `<main>' To see why this extension failed to compile, please check the mkmf.log which can be found here: /Users/koichi/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/extensions/x86_64-darwin-19/2.3.0-static/therubyracer-0.12.3/mkmf.log extconf failed, exit code 1 Gem files will remain installed in /Users/koichi/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/gems/therubyracer-0.12.3 for inspection. Results logged to /Users/koichi/.rbenv/versions/2.3.4/lib/ruby/gems/2.3.0/extensions/x86_64-darwin-19/2.3.0-static/therubyracer-0.12.3/gem_make.outこのエラーを読んで、
- therubyracer でエラー
- libv8 も絡んでる
- option をつけろ
ということかと?
3つの手順で解決
1 - V8 の 3.15 を入手
brew install v8@3.15
2 - ローカルの設定ファイルへ書き込み
bundle config --local build.libv8 --with-system-v8 bundle config --local build.therubyracer --with-v8-dir=/usr/local/opt/v8@3.15
3 - インストール
bundle install
これでうまくいきました??
解決方法にたどり着くまでに調べたこと
以下、まとまってないです. メモとして残してます
therubyracer
Call JavaScript code and manipulate JavaScript objects from Ruby. Call Ruby code and manipulate Ruby objects from JavaScript.
- 2017年のver0.12.3で止まっている
- 依存関係: libv8 ~> 3.16.14.0 つまり 3.16.14.0 から 3.16.14.19 まで
- mini racer??
libv8
Distributes the V8 JavaScript engine in binary and source forms in order to support fast builds of The Ruby Racer
バージョン履歴
- 7.3.492.27.1 - July 22, 2019 universal-darwin19 (6.99MB)
- 7.3.492.27.1 - July 22, 2019 x86_64-darwin-19 (6.99MB)
- 3.16.14.19 - January 11, 2018 universal-darwin-17 (2.36MB)
mini racer
Minimal embedded v8 engine for Ruby
依存性
libv8 >= 6.9.411
Darwinって?
Darwin(ダーウィン)はアップルが開発するUnix系のPOSIX準拠オペレーティングシステム (OS) である。技術的にはNEXTSTEPからOPENSTEPに続く流れを汲み、Mach 3.0+BSDをベースとし、一部の機能は他のBSD系OSからも取り入れている。DarwinはmacOSやiOS、さらにはwatchOSとtvOSの基礎となる部分でもある。
自分のMac環境(2020-01-21現在)
- Darwin Kernel Version 19.2.0
V8 javascript engine
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and in Node.js, among others. It implements ECMAScript and WebAssembly, and runs on Windows 7 or later, macOS 10.12+, and Linux systems that use x64, IA-32, ARM, or MIPS processors. V8 can run standalone, or can be embedded into any C++ application.
疑問
v8 engine に ”3.15系統” と ”最新の7系統” がある?自分のGoogle Chrome のバージョンをしらべるには?
chromeバージョン確認ページ
自分のChromeのバージョンを確認したところ↓
JavaScript: V8 7.9.317.32もう一度、
brew install v8
の参考ページをよく見ると
バージョン3.15
はopen sourceとなってる
対して、7.9
にはついていない
3系統だけopen source?libv8のreadme
ここに次のような記載がありますVersioning
Versions of the libv8 gem track the version of v8 itself, adding its own point release after the main v8 version. So libv8 3.11.8.5 and 3.11.8.14 both correspond to v8 version 3.11.8. Another way to think about it would be that 3.11.8.14 is the 14th release of the libv8 rubygem based on v8 version 3.11.8つまり、V8のバージョン番号がほぼそのままlibv8のバージョン番号になっているということ
% brew info v8 v8: stable 7.9.317.31 (bottled) Google's JavaScript engine https://github.com/v8/v8/wiki /usr/local/Cellar/v8/7.9.317.31 (38 files, 38.9MB) * Poured from bottle on 2020-01-22 at 11:43:33 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/v8.rb ==> Dependencies Build: ninja ✘ ==> Requirements Build: xcode ✔ ==> Analytics install: 2,444 (30 days), 10,549 (90 days), 38,848 (365 days) install-on-request: 2,138 (30 days), 8,718 (90 days), 28,839 (365 days) build-error: 0 (30 days)その他参考にしたサイト
https://github.com/rubyjs/therubyracer/issues/455
https://bundler.io/v1.16/bundle_config.html
https://formulae.brew.sh/api/formula/v8@3.15.json
- 投稿日: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-23T12:11:06+09:00
【Railsでスクレイピング】Mechanize記事まとめ
- 投稿日:2020-01-23T12:07:46+09:00
【Rails】 Heroku, Aws で詰まったときに見る記事まとめ
Heroku
db
heroku pg:reset DATABASE_URL heroku run rake db:migrate or heroku run rake db:seed【Rails】Heroku上でApplication Error(H10 App crashed)【PostgreSQL】
group :production do gem 'pg', '0.20.0' endメモ
heroku run rails c
でheroku上のdbの中身を確認できる。
heroku run rails db:migrate:status
でdbの状態を見れる。
heroku logs -t
で詳しいエラー内容を見れる。assets
Rails4 asset pipeline関連設定まとめ(Heroku対応込)
RAILS_ENV=production bundle exec rake assets:precompile assets:clean git add . git commit -m "hoge" git push origin hoge git push heroku【rails】【heroku】【bootstrap】herokuでCSS、font、JavaScriptが反映されない。
credentials.yml.enc, master.key
【Rails5.2】credentials.yml.encとmaster.keyでのデプロイによる今までとの変更点
EDITOR=vim bin/rails credentials:editrailsのエラー「Errno::EACCES: Permission denied」の解決
production環境でsecret_tokenをセットする(rails)
AWS
- 投稿日:2020-01-23T11:49:46+09:00
あっさり読むrails④(非同期通信)
はじめに
JSを使った非同期通信を簡単に書いてみます。
前提
使用するのは、
Ruby on rails
Haml
jQuery
です。
CSSは特に指定しません。実行
次のファイルを用意します。
sample.haml.html= form_with model:@sample, local: true do |f| = f.text_area :name, placeholder: "サンプル", class: "sample-form" .add-textこれがビューデータとなります。
sample.js$(function(){ $(".sample-form").on("change" functon(){ var sampletext = $(this).val; $(".add-text").text(sampletext): }) });これが非同期処理の中身になります。
これで、テキストエリアに文章を入力すれば、同じ文章が
.add-text
の部分に表示されます。※随時更新します
- 投稿日:2020-01-23T11:49:46+09:00
あっさり読むrails④(非同期処理)
はじめに
JSを使った非同期処理を簡単に書いてみます。
関連事項を次の記事に書いています。前提
使用するのは、
Ruby on rails
Haml
jQuery
です。
CSSは特に指定しません。実行
次のファイルを用意します。
Gemfilegem 'jquery-rails'これを記述して、
bundle install
します。
(ディレクトリが、アプリのディレクトリになっている事を確認。pwd
というコマンドで確認可能)application.js//= require jqueryこの記述を忘れるとエラーになります(
$とは何ですか?
という感じのエラー)sample.haml.html= form_with model:@sample, local: true do |f| = f.text_area :name, placeholder: "サンプル", class: "sample-form" .add-textこれがビューデータとなります。
sample.js$(function(){ $(".sample-form").on("change" functon(){ var sampletext = $(this).val; $(".add-text").text(sampletext): }) });これが非同期処理の中身になります。
これで、テキストエリアに文章を入力すれば、同じ文章が
.add-text
の部分に表示されます。※随時更新します
- 投稿日:2020-01-23T11:37:46+09:00
複数のレコードを一括処理
一括でレコードをアレコレするやり方。なお割と力技。
それぞれやりたい事は以下。①カートを空にする =Userに紐づくCartレコードを全削除
②カートに入ってる商品を注文する =複数のCartレコードを使って複数のOrderProductレコードを作成する。
③注文情報と注文商品情報をまとめて変更する =親要素と子要素を一括でupdateをかける前提ーー
Cartモデル、OrderProductモデルには以下のカラムがある
・product_name
・quantity
・price
・order_id(OrderProductのみ)
・status(OrderProductのみ)
Orderモデル
・user_id
・statusUser<Cart,Order
Order<OrderProduct が1対他の関係。①カートを空にする
delete_allメソッドを使う。これを使うとUserに紐づいたCartレコードを全て削除できる。
似たようなものでDestroy_allがあるけどこちらはUserに紐づいた全てのレコードが削除されるらしい。つまりこの前提だとOrderレコードまで消えるっぽい。
actionはdestroyを個別削除に使っていたので新しく作成する。config/routes.rbdelete 'public/carts' => "public/carts#delete_all"carts_controller.rbdef delete_all @user = current_user @user.carts.delete_all endCarts/index.html.erb<%= link_to "カートを空にする", public_carts_path, method: :delete %>②カートに入ってる商品を注文する
ここでやりたい挙動は
1、Orderレコードを新しく作成
2、そのIDを使ってOrderProductを作成controllerdef create @user = current_user @order = Order.new @order.user_id = current_user.id @order.save! @user.carts.each do |cart| order_product = OrderProduct.new order_product.order_id = @order.id order_product.quantity = cart.quantity order_product.product_name = cart.product_name order_product.total = cart.product.price order_product.save end endもっと大量のデータを扱う場合は別のやり方があると思う。
.eachで回すのはナンセンスだけどやり方調べる時間がなかった。③注文情報と注文商品情報をまとめて変更する
これが一番難しかった。何なら今でもいまいち理解できてない。
order_controllerdef update @order = Order.find(params[:id]) @order.update(order_params) end private def order_params params.require(:order).permit(:user_id,:status, order_products_attributes: [:id, :status, :_destroy]) endmodels/order.rbaccepts_nested_attributes_for :order_products<%= form_for [@order] do |f| %> <%= f.select :status, ['入金待ち', '入金確認', '製作中', '発送準備中', '発送済み'], {}, class: "dropdown" %> <%= f.fields_for :order_products do |order_product| %> <%= order_product.select :status, ['着手不可', '製作待ち', '製作中', '製作完了'] %> <% end %> <%= f.submit "更新" %> <% end %>order_products_attributes: [:id, :status, :_destroy]
まず一番にcontrollerのこいつ。order_paramsに入りこんでるこいつ。attributesを使うならこれとモデルへの記述が必要でidと_destroyは形式として突っ込むらしい。何故かはよくわからない。それからfields_for。これをform_forの中にとりあえず入れると、そこで子要素を編集できる。fields_forをかけると子要素のレコードを繰り返し持ってこれるので.eachはいらない。ただし
タグで:product_nameなんかを表示させる為に.eachも併用すると途端にテーブルが崩壊する。そういう場合はもうテーブルを分ける。入力のテーブルと商品名とかを表示させるテーブルをいい感じにくっつける。
submitはform_forの中且つfields_forの外。
これでいける。
え、同じ値を全レコードのカラムにぶち込みたい?
.eachで .カラム = "入れたい値" を回せばいいんじゃないかな。
createならsaveする前に入れてさ。
- 投稿日:2020-01-23T11:22:02+09:00
【Rails】scope、ActiveSupport::Concernについて
環境
Rails 5.2.3
mysql 5.7.28
リテラルについて
例文
contoroller.rbdef index @boards = Board.includes(:user).order('created_at DESC') end def bookmarks @bookmarks = current_user.bookmarks.board.includes(:user).order('created_at DESC') end改善ポイント
・orderはリテラルではなくscopeで定義すべき理由
・共通化できるクエリはscopeでメソッドのように定義すべき
・クエリはできるだけリテラルで使わないほうが良い
リテラル=変数やメソッド化していないただのベタ書きした文字や数字メリット
・任意のメソッド名でどのような効果を持つかわかりやすくなる
・探す場所が1箇所に絞られ、リファクタリング容易(保守性)、データベースパフォーマンスの最適化(読み込みスピードUP)が図れる
・IDEの構文チェックがうまく走らないことがあり、ミスに気づけなくなることがある。scope
共通的に使うクエリーをメソッドのように定義することができる便利な機能。
board.rbscope :new_order, -> { order(created_at: :desc) }contoroller.rbdef index @boards = Board.includes(:user).new_order end def bookmarks @bookmarks = current_user.bookmarks.board.includes(:user).new_order endこのようにscopeを使用することで先ほどあげたメリットがある。
しかし、システムが大きくなるほどscopeの数が増えていき見通しが悪くなる。
そんな時にActiveSupport::Conernを使ってmoduleに機能を切り出す。ActiveSupport::Concern
共通処理をモジュールとして切り出し、インクルードすることでモジュールを使用。
例文
board.rbscope :new_order, -> { order(created_at: :desc) }comment.rbscope :new_order, -> { order(created_at: :desc) }複数のモデルで同じscopeが定義されている時、ActiveSupport::Concernでまとめる。
引用
1. app/models/concerns/以下のモジュールファイルを作成する
2. ActiveSupport::Concernモジュールをextendで取り込む
3. includedブロック内でscopeを宣言する
4. モデル側でモジュールをincludeするapp/models/concerns/hoge.rbrequire 'active_support' module Hoge extend ActiveSupport::Concern included do scope :new_order, -> { order(created_at: :desc) } end endboard.rb,comment共通include Hogeまとめ
参考資料
Rails: モデルの外では名前付きスコープだけを使おう(翻訳)
scopeをActiveSupport::Concernに分割する
[Rails] ActiveSupport::Concern の存在理由
- 投稿日: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 ファイルの作り方の記事になってしまっています。
使い方が全くわからないという方には少しは参考になるかなーと思い投稿させていただきました。